如何在线程池中停止线程

时间:2010-09-23 11:22:06

标签: java

我正在编写一个产生多个并发任务的应用程序。我正在使用线程池来实现它。

可能会发生一个事件,使得在任务中完成的计算无效。在这种情况下,我想停止当前正在运行的任务,并开始新的任务。

我的问题:如何停止当前正在运行的任务?我实现的解决方案是存储对任务线程的引用,并在此线程上调用interrupt()。在演示代码中:

public class Task implements Runnable {

    private String name;
    private Thread runThread;

    public Task(String name) {
        super();
        this.name = name;
    }

    @Override
    public void run() {
        runThread = Thread.currentThread();

        System.out.println("Starting thread " + name);
        while (true) {
            try {
                Thread.sleep(4000);
                System.out.println("Hello from thread " + name);
            } catch (InterruptedException e) {
                // We've been interrupted: no more messages.
                return;
            }
        }
    }

    public void stop() {
        runThread.interrupt();
    }

    public String getName() {
        return name;
    }
}

主要方法是:

public static void main(String args[]) {
    executorService = Executors.newFixedThreadPool(2);

    Task t1 = new Task("Task1");
    Task t2 = new Task("Task2");
    executorService.execute(t1);
    executorService.execute(t2);
    executorService.execute(new Task("Task3"));
    executorService.execute(new Task("Task4"));

    try {
        Thread.sleep(12000);
        t1.stop();
        System.err.println("Stopped thread " + t1.getName());
        Thread.sleep(8000);
        t2.stop();
        System.err.println("Stopped thread " + t2.getName());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

这是一个很好的解决方案,还是有更好的方法来阻止线程池中正在运行的线程?

4 个答案:

答案 0 :(得分:3)

您的方法背后的想法是几个正确的解决方案之一。 Dealing with InterruptedException给出了如何使用中断机制的一个很好的概述。当您进行长计算时,此机制主要有用。另外要记住的是,其他库有可能通过不执行指南所说的内容来破坏您的中断机制(当它们没有处理它时不重置中断状态等)。

请注意,您的Task类不是线程安全的。你可以在保存currentThread之前停止任务,这会产生NullPointerException。

更简单的方法是设置volatile boolean变量running,而不是while(true)循环执行while(running)方法(但这更为通用)。

要看的另一件事是FutureTask机制,因为它已经有一个使用中断机制的取消机制。

答案 1 :(得分:2)

在您重写的run()方法中,您将使用while(true)永久循环。标准行为是boolean runIndicatorrun()方法在启动时设置为true,然后您的循环应为while(runIndicator)。您的stop()方法应该简单设置runIndicator = false,这样循环的下一次迭代就会失败。

答案 2 :(得分:2)

你可以通过持有对未来的引用来阻止它

          Future<?> future = exec.submit( new Runnable() {
      while (true){
        try{ 
          obj.wait();
      }catch(InterruptedException e){
          System.out.println("interrupted");
          return;
       }
      });
      future.cancel(true);

布尔值是 - 如果正在运行可能会中断。

我测试了并从该线程中获得了一个中断的异常。

如果您有cachedThreadPool,您可能需要仔细检查是否在runnable中捕获了异常,然后不要将标志设置为中断,因为您的线程将运行另一个未来,如果您设置了中断,则其他队列将来可能不会跑。

答案 3 :(得分:1)

应该使用

executorService.shutdown()和executorService.shutdownNow()来关闭线程池以正常退出应用程序。请参阅ExecutorService

请参阅Qwerky的答案,以结束当前正在运行的线程。