java 在 ExecutorService 任务中停止无限循环
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2358139/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Stop an infinite loop in an ExecutorService task
提问by java_geek
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());
}
}
}
Is there a way in which i can stop the thread executing the infinite loop?
有没有办法可以停止执行无限循环的线程?
回答by erickson
Yes, you can replace flag(or logically &&) with !Thread.currentThread().isInterrupted().
是的,你可以更换flag(或逻辑&&与)!Thread.currentThread().isInterrupted()。
This way, when the task is canceled,the loop will be terminated.
这样,当任务被取消时,循环就会终止。
The loop would look something like this:
循环看起来像这样:
while(!Thread.currentThread().isInterrupted() && flag) {
/* Do work. */
}
Use should be something like this:
使用应该是这样的:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> task = executor.submit(new Task());
String str;
try {
str = task.get(5, TimeUnit.SECONDS);
} finally {
task.cancel(true);
}
回答by Chris Dennett
Think about using synchronized (this) { this.wait() }instead of sleepinside call(), and then when you set the boolean flagexternally (perhaps directly or via a flag()method; with direct access make sure your flag variable is volatile) call task.notifyAll()to wake up the sleeping thread (make sure your task object is a local variable instead of having it anonymous so that you can call methods on it, and make flag a class attribute within Task).
考虑使用synchronized (this) { this.wait() }而不是sleepinside call(),然后当您在flag外部设置布尔值时(可能直接或通过flag()方法;直接访问确保您的标志变量是volatile)调用task.notifyAll()唤醒睡眠线程(确保您的任务对象是局部变量而不是让它匿名,以便您可以调用它的方法,并在 中标记一个类属性Task)。
It'll also be more efficient like that because loops waste cycles needlessly -- the exact mechanism is called a 'guarded block' (http://java.sun.com/docs/books/tutorial/essential/concurrency/guardmeth.html). When you wake up out of the wait, test for the flag variable just to make sure it was set.
它也会更高效,因为循环会不必要地浪费循环——确切的机制称为“受保护的块”(http://java.sun.com/docs/books/tutorial/essential/concurrency/guardmeth.html)。当您从等待中醒来时,测试标志变量以确保它已设置。
Edit: looked at the original question more closely and created an example using the existing code and principles (there's more than one way to skin a cat :)). Try this -- the loop here exits due to the interrupted status of the current thread, which has been canceled due to timeout:
编辑:更仔细地查看原始问题并使用现有代码和原则创建了一个示例(有不止一种方法可以给猫剥皮:))。试试这个——这里的循环由于当前线程的中断状态而退出,由于超时而被取消:
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();
}
}
}
}

