我正在编写一个产生多个并发任务的应用程序。我正在使用线程池来实现它。
可能会发生一个事件,使得在任务中完成的计算无效。在这种情况下,我想停止当前正在运行的任务,并开始新的任务。
我的问题:如何停止当前正在运行的任务?我实现的解决方案是存储对任务线程的引用,并在此线程上调用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();
}
}
这是一个很好的解决方案,还是有更好的方法来阻止线程池中正在运行的线程?
答案 0 :(得分:3)
您的方法背后的想法是几个正确的解决方案之一。 Dealing with InterruptedException给出了如何使用中断机制的一个很好的概述。当您进行长计算时,此机制主要有用。另外要记住的是,其他库有可能通过不执行指南所说的内容来破坏您的中断机制(当它们没有处理它时不重置中断状态等)。
请注意,您的Task
类不是线程安全的。你可以在保存currentThread
之前停止任务,这会产生NullPointerException。
更简单的方法是设置volatile boolean
变量running
,而不是while(true)
循环执行while(running)
方法(但这更为通用)。
要看的另一件事是FutureTask
机制,因为它已经有一个使用中断机制的取消机制。
答案 1 :(得分:2)
在您重写的run()
方法中,您将使用while(true)
永久循环。标准行为是boolean runIndicator
,run()
方法在启动时设置为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的答案,以结束当前正在运行的线程。