简体   繁体   English

在ExecutorService任务中停止无限循环

[英]Stop an infinite loop in an ExecutorService task

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? 有没有办法让我可以阻止线程执行无限循环?

Yes, you can replace flag (or logically && ) with !Thread.currentThread().isInterrupted() . 是的,你可以用!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);
}

Think about using synchronized (this) { this.wait() } instead of sleep inside call() , and then when you set the boolean flag externally (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() }而不是在call()内部sleep ,然后在外部设置布尔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 ). 它也会更有效,因为循环浪费不必要的循环 - 确切的机制被称为'保护块'( 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. 当您从等待中醒来时,测试标志变量只是为了确保它已设置。

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();
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM