如何在线程池中停止线程

时间:2021-06-17 07:12:10

I'm writing an application that spawns multiple concurrent tasks. I'm using a thread pool to implement that.

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

It may happen that an event occurs that renders the computations being done in the tasks invalid. In that case, I would like to stop the currently running tasks, and start new ones.

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

My problem: How do I stop the currently running tasks? The solution I implemented is to store a reference to the task thread and call interrupt() on this thread. In demo code:

我的问题:如何停止当前正在运行的任务?我实现的解决方案是存储对任务线程的引用并在该线程上调用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;
    }
}

And the main method is:

主要方法是:

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

Is this a good solution, or is there a better way to stop a running thread in a thread pool?

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

4 个解决方案

#1


3  

The idea behind your approach is one of the several correct solutions. Dealing with InterruptedException gives a great rundown on how you should use the interrupt mechanism. This mechanism is mainly useful when you are long computations. One other thing to keep in mind is that it is possible for other libraries to spoil your interrupt mechanism by not doing what the guide says (not resetting the interrupt state when they haven't handled it etc).

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

Do note that your Task class isn't thread-safe. You could be stopping the task before saving the currentThread, which would give a NullPointerException.

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

A much simpler approach is to set a volatile boolean variable running and instead of a while(true) loop doing a while(running) approach (this is however much more general).

一种更简单的方法是设置一个运行的volatile布尔变量,而不是一个while(true)循环执行while(running)方法(这是更常见的)。

Another thing to look at is the FutureTask mechanism, as this already has a canceling mechanism that uses the interrupt mechanism.

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

#2


2  

In your overridden run() method you loop forever with while(true). The standard behaviour would be to have a boolean runIndicator which the run() method sets to true when it starts, and your loop should then be while(runIndicator). Your stop() method should simple set runIndicator = false so the next iteration of the loop will fall out.

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

#3


2  

You can stop it by holding a reference to that future

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

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

boolean is for - may interrupt if running.

boolean用于 - 如果正在运行可能会中断。

I tested out and got an interrupted exception from that thread.

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

If you have cachedThreadPool you may want to double check that you catch the exception in your runnable, and then don't set back the flag interrupted, because your thread will run another future, if you set interrupt, the other queue future may not run.

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

#4


1  

executorService.shutdown() and executorService.shutdownNow() should be used to shutdown the thread pool to gracefully exiting the application. See ExecutorService.

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

See Qwerky's answer for ending the currently running thread.

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

#1


3  

The idea behind your approach is one of the several correct solutions. Dealing with InterruptedException gives a great rundown on how you should use the interrupt mechanism. This mechanism is mainly useful when you are long computations. One other thing to keep in mind is that it is possible for other libraries to spoil your interrupt mechanism by not doing what the guide says (not resetting the interrupt state when they haven't handled it etc).

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

Do note that your Task class isn't thread-safe. You could be stopping the task before saving the currentThread, which would give a NullPointerException.

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

A much simpler approach is to set a volatile boolean variable running and instead of a while(true) loop doing a while(running) approach (this is however much more general).

一种更简单的方法是设置一个运行的volatile布尔变量,而不是一个while(true)循环执行while(running)方法(这是更常见的)。

Another thing to look at is the FutureTask mechanism, as this already has a canceling mechanism that uses the interrupt mechanism.

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

#2


2  

In your overridden run() method you loop forever with while(true). The standard behaviour would be to have a boolean runIndicator which the run() method sets to true when it starts, and your loop should then be while(runIndicator). Your stop() method should simple set runIndicator = false so the next iteration of the loop will fall out.

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

#3


2  

You can stop it by holding a reference to that future

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

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

boolean is for - may interrupt if running.

boolean用于 - 如果正在运行可能会中断。

I tested out and got an interrupted exception from that thread.

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

If you have cachedThreadPool you may want to double check that you catch the exception in your runnable, and then don't set back the flag interrupted, because your thread will run another future, if you set interrupt, the other queue future may not run.

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

#4


1  

executorService.shutdown() and executorService.shutdownNow() should be used to shutdown the thread pool to gracefully exiting the application. See ExecutorService.

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

See Qwerky's answer for ending the currently running thread.

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