我希望在给定超时后停止/终止Threads (Runnables)
启动的所有Main
。我试着像下面提到的那样做。但它没有按预期工作。除此之外,我尝试使用Thread.interrupt()
,但结果是否定的。我试过thread.stop()。它正在运行但已被弃用。
有人能对此有所了解吗?
注意:我专注于Runnables
而不是Callables
的解决方案。我试图通过仅修改客户端代码(Main
)来做到这一点。不是Threads
(供应商)
主要
Thread roxtoursThrd = new Thread(new Supplier("roxtours", 1));
Thread bluevacationsThrd = new Thread(new Supplier("bluevacations", 1));
Thread elixerThrd = new Thread(new Supplier("elixer", 1));
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
taskExecutor.execute(roxtoursThrd);
taskExecutor.execute(bluevacationsThrd);
taskExecutor.execute(elixerThrd);
taskExecutor.shutdown();
// taskExecutor.shutdownNow(); // This is also not stopping threads. They continue.
try {
taskExecutor.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
Supplier.java
public class Supplier implements Runnable {
public Supplier(String name, int count) {
this.name = name;
this.count = count;
}
@Override
public void run() {
try {
// Some time consuming operations (URL Connections, XML Decoding, DB Queries etc etc) are goes in here.
} catch (Exception e) {
e.printStackTrace();
}
}
String name = null;
int count = 0;
Logger logger = Logger.getLogger(Supplier.class);
}
答案 0 :(得分:4)
让执行者的任务响应中断将需要更改供应商的代码。中断是合作的;被中断的线程会在其上设置一个标志,但由线程决定如何处理它。如果你的Runnable不对它起作用,就像在你的例子中一样,那么没有任何反应,线程就会继续执行。
Executor只能取消响应中断的线程,请参阅the API documentation for ExecutorService.shutdownNow:
除了尽力尝试停止处理主动执行任务之外,没有任何保证。例如,典型的实现将通过Thread.interrupt()取消,因此任何无法响应中断的任务都可能永远不会终止。
线程可以使用Thread#isInterrupted方法检查其标志。您的Runnable任务应该检查Thread.getCurrentThread().isInterrupted()
。
如果一个线程在设置了中断标志时正在等待或休眠,那么将抛出InterruptedException并清除该标志。
不要使用Thread#setDaemon(true),除非你已经准备好让这些线程在没有警告的情况下突然消失,并且当应用程序的其余部分关闭时没有机会清理待处理的任务。
另一个选项是不推荐使用的Thread#stop方法,它会导致抛出ThreadDeath。与中断不同,这是不合作的,并且编写可以在发生此异常时可预测且干净地终止的代码是困难的,也是不可能的,因为ThreadDeath可以被抛出任何地方,与InterruptedException不同,InterruptedException更易于管理,因为它只是从特定的抛出阻止电话。
答案 1 :(得分:2)
使用shutdownNow()
代替shutdown()
。
shutdown()
将启动关闭,它不会接受任何新任务,但您永远不知道线程何时会被实际停止。
shutdownNow()
将立即尝试停止所有活动线程,这将返回正在等待执行的所有活动线程。
同样不能保证所有线程都会立即停止(线程将进行正常关闭,并且根据给予线程的任务可能需要一些时间)。我们必须使用以下任一方法等待所有线程完成执行。
executor.awaitTermination(...);
或
while (! executor.isTerminated()) {
// Sleep for few milliseconds...
}
请参阅文档:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#shutdown%28%29
答案 2 :(得分:1)
如果要中断线程,则必须提供中断入口点。例如,睡眠很短的时间,然后抓住并处理InterruptionException
。
接下来你要做的就是在每次迭代中都使用isInterrupted()
方法,也可以使用句柄。
其他方法是使所有线程守护进程都使用setDaemon()
,因为它们将在主线程完成后被杀死,但这只有在要停止main时才有用。
回复您的编辑/更新问题:
摘自shutdownNow()
文档
除了努力尝试停止处理之外,没有任何保证 积极执行任务。例如,典型的实现方式 通过Thread.interrupt()取消,因此任何无法响应的任务 中断可能永远不会终止。
因此,要么您准备应用程序以作为多线程工作,要么您坚持使用单线程。
另请参阅How do you kill a thread in Java?。
以上问题中最重要的链接:http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html
答案 3 :(得分:1)
您的线程的run方法没有阻塞,因此它不会遇到抛出InterruptedException的情况。
当一个线程被篡改时,除了在阻塞时抛出一个异常,它还会设置其中断状态,也就是说Thread#isInterrupted()方法返回true。此外,Thread#interrupted方法也返回true,但是后者将清除线程的中断状态。
在您的示例中,您没有阻止,也没有检查线程的中断状态。
编辑:既然你没有检查线程是否被中断,也没有阻塞,那么你就不能显式地停止线程,但你可以通过使它们成为守护程序线程然后当你的主线程来阻止它们(这是一个用户线程)完成后,所有其他守护程序线程将停止。守护程序线程和用户线程之间的主要区别在于,只要所有用户线程完成执行java程序或JVM终止自身,JVM就不会等待守护程序线程完成执行。