如果未在5秒内完成,我想启动一个线程并取消它:
private final class HelloWorker implements Callable<String> {
public String call() throws Exception {
while(true) {
if (Thread.isInterrupted()) {
return null;
}
}
return performExpensiveComputation();
}
private String performExpensiveComputation() {
// some blocking expensive computation that may or may not take a very long time
}
}
private ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);
Future<String> future = executorService.submit(new HelloWorker());
try {
String s = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
future.cancel(true);
System.out.println("cancelled: " + future.isCancelled() + "done: " + future.isDone());
executorService.shutdown();
try {
System.out.println("try to terminate: " + executorService.awaitTermination(60, TimeUnit.SECONDS));
} catch (Exception ex) {
// ignore
}
}
然而,看起来awaitTermination返回false。有没有办法让我检查为什么ExecutorService不会终止?我可以找出仍在运行的线程吗?
答案 0 :(得分:2)
为什么Future.cancel()无法按您认为的方式工作
将来取消将从正在运行的队列中删除任务。如果您的任务已经在运行,它将不会停止它。因此, cancel()是一个与中断不同的概念。正如Javadocs所说:
尝试取消执行此任务。如果此尝试将失败 任务已经完成,已经被取消或者可能 不会因为其他原因而被取消。如果成功了,这个任务 调用cancel时尚未启动,则该任务永远不会运行。如果 任务已经开始,那么mayInterruptIfRunning参数 确定执行此任务的线程是否应该 试图停止任务而中断。 https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/concurrent/Future.html#cancel(boolean)
您要问的是如何打断。幸运的是,当您调用 Future.cancel()时,它将调用中断方法。但是您需要允许它与mayInterruptIfRunning标志一起使用,并且需要正确处理中断(请参见下文)。
为什么要打扰?
当您需要长时间运行的任务现在需要停止时,或者当您有需要关闭的守护程序以及其他示例时,使用Java中的中断线程很有用。
如何打扰
要中断,请在线程上调用interrupt()。这是一个合作过程,因此您的代码必须为此做好准备。像这样:
myThread.interrupt();
负责的代码
您的代码的责任是为任何干扰做好准备。我想说的很久了,只要您有一个长期运行的任务,就插入一些中断准备好的代码,如下所示:
while (... something long...) {
... do something long
if (Thread.interrupted()) {
... stop doing what I'm doing...
}
}
如何停止我在做什么?
您有几种选择:
private void someMethodDeepDown() {
while (.. long running task .. ) {
... do lots of work ...
if (Thread.interrupted()) {
// oh no! an interrupt!
Thread.currentThread().interrupt();
throw new SomeOtherException();
}
}
}
现在,异常可以传播终止线程或被捕获的异常,但是接收代码有望注意到正在进行中断。
我应该使用isInterrupted()还是interrupted()
您应该首选 interrupted(),因为:
为什么要使用interrupt()为什么在我的代码中不添加其他标志?
中断是最好的中断机制,因为我们的代码可以为之做好准备。如果我们发现只是捕获并忽略了 InterruptException 的代码,或者没有在其主体中检查 interrupted()的代码,则可以纠正这些错误,并使我们的代码始终清晰可中断无需在代码中创建对非标准机制的神秘依赖。
不幸的是,约书亚·布洛克(Joshua Block)在他的着名著作《有效Java,第二版》中提出了相反的说法。但是我相信启用 interrupt()方法可以按预期工作会更好。
答案 1 :(得分:1)
没有安全的方法来阻止正在运行的线程而不会影响其余进程的稳定性。这就是很久以前{@ 1}}被弃用的原因,也是Executor Services仅使用软协作Thread#stop
机制的原因。
您的线程必须主动检查是否已请求中断并在结束前执行适当的清理。或者,线程将调用一些可中断的JDK方法,这些方法将抛出Thread#interrupt
,胎面将正确地尊重并结束自己。