import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
class Task implements Callable<String> {
public String call() throws Exception {
String s = "initial";
try {
System.out.println("Started..");
/*for (int i=0;i<10000;i++) {
if (i % 2 == 0) {
System.out.println("Even");
}
}*/
boolean flag = true;
while(flag) {
}
System.out.println("Finished!");
s = "Done";
}
catch (RuntimeException e) {
s = "RuntimeException";
}
catch (Exception e) {
s = "Exception";
}
finally {
}
return s;
}
}
public class ExecutorServiceTest {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
List<Future<String>> result = executor.invokeAll(Arrays.asList(new Task()), 5, TimeUnit.SECONDS);
executor.shutdown();
Iterator<Future<String>> iter = result.iterator();
while (iter.hasNext()) {
System.out.println("Came here");
Future<String> fut = iter.next();
System.out.println(fut.get());
}
}
}
Существует ли путь, которым я могу остановить поток, выполняющий бесконечный цикл?
Да, вы можете заменить флаг
(или логически &&
) на ! Thread.currentThread (). isInterrupted ()
.
Таким образом, когда задача отменена, цикл будет завершен.
Цикл будет выглядеть примерно так:
while(!Thread.currentThread().isInterrupted() && flag) {
/* Do work. */
}
Использование должно быть примерно таким:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> task = executor.submit(new Task());
String str;
try {
str = task.get(5, TimeUnit.SECONDS);
} finally {
task.cancel(true);
}
Подумайте об использовании synchronized (this) {this.wait ()}
вместо sleep
внутри call ()
, а затем при установке логического флаг
извне (возможно, напрямую или с помощью метода flag ()
; при прямом доступе убедитесь, что ваша переменная флага volatile
) call task.notifyAll ( )
, чтобы разбудить спящий поток (убедитесь, что ваш объект задачи является локальной переменной, а не анонимной, чтобы вы могли вызывать для него методы, и установите флаг для атрибута класса в Task
).
Это также будет более эффективным, потому что циклы тратятся напрасно - точный механизм называется «охраняемым блоком» ( http://java.sun.com/docs/books/tutorial/essential /concurrency/guardmeth.html). Когда вы просыпаетесь после ожидания, проверьте переменную флага, чтобы убедиться, что она установлена.
Редактировать: более внимательно рассмотрел исходный вопрос и создал пример, используя существующий код и принципы (есть несколько способов снять шкуру с кошки :)). Попробуйте это - цикл здесь завершается из-за состояния прерывания текущего потока, который был отменен из-за тайм-аута:
package ett;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
class Task implements Callable<String> {
public String call() throws Exception {
String s = "initial";
System.out.println("Started..");
for (int i=0;;i++) {
if (i % 2 == 0) {
System.out.println("Even");
}
Thread.yield();
if (Thread.interrupted()) break;
}
System.out.println("Finished!");
s = "Done";
return s;
}
}
public class ExecutorServiceTest {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
List<Future<String>> result = executor.invokeAll(Arrays.asList(new Task()), 1, TimeUnit.SECONDS);
executor.shutdown();
System.out.println("came here");
for (Future<String> f : result) {
try {
System.out.println(f.get());
} catch (CancellationException e) {
e.printStackTrace();
}
}
}
}