executorService.shutdownNow()不会停止该线程

时间:2016-08-08 10:34:31

标签: java multithreading scheduledexecutorservice

我有一个预定的Executor服务设置,如

<div class="btn-group pull-right" data-toggle="buttons" style="top:26px;z-index:2;">
<label class="make-small btn btn-default" id="first_button_func">
<span>First Button</span>
</label>
<label class="make-small filter-column btn btn-default active">
<input type="checkbox" autocomplete="off" checked=""> <span>Second Button</span>
</label>
</div>

要停止此线程,我调用close方法,但线程通常不会停止。我不确定是什么错,如果我不知道我应该在我的run()代码中处理class Test { private final ScheduledExecutorService executor; public Test() { executor = Executors.newSingleThreadScheduledExecutor((runnable) -> { Thread thread = new Thread(runnable, this.getClass().getName()); thread.setDaemon(true); return thread; }); executor.scheduleWithFixedDelay( new TestRefreshTask(), 0, 50000, TimeUnit.MILLISECONDS ); } private class TestRefreshTask implements Runnable { @Override public void run() { //refresh some data refreshdata(); } } public void close() { executor.shutdown(); try { if(!executor.awaitTermination(60, TimeUnit.SECONDS)) { executor.shutdownNow(); executor.awaitTermination(60, TimeUnit.SECONDS)); } } catch (InterruptedException e) { //Retry to dispose task executor.shutdownNow(); Thread.currentThread().interrupt(); throw new RuntimeException(e); } } }

1 个答案:

答案 0 :(得分:1)

  • 线下的真正解决方案。这部分只描述了陷阱。

来自shutdownNow()的javadoc:

  

除了尽力尝试停止处理主动执行任务之外,没有任何保证。例如,典型的实现将通过Thread.interrupt取消,因此任何无法响应中断的任务可能永远不会终止

根据经验,线程确实会被打断,但根据此文档,即使这样也无法保证。

但是,您的任务不是您自己控制的,而是在scheduleWithFixedDelay()内创建的私人任务。

来自scheduleWithFixedDelay()的javadoc:

  

如果任务的任何执行遇到异常,则后续执行被禁止。 否则,任务只会通过取消或终止执行人来终止。

这意味着shutdownNow()不会停止该线程。取消部分对我来说有点不清楚,因为Runnable而不是Future,没有cancel()方法。任务停止的另一个原因是终止执行程序,但是只有在任务停止时才会终止池。

真正的解决方案潜伏在ScheduledThreadPoolExecutor

的javadoc中
  

默认情况下,此类已取消的任务不会自动从工作队列中删除,直到其延迟结束。虽然这可以进一步检查和监控,但它也可能导致取消任务的无限制保留。要避免这种情况,请将setRemoveOnCancelPolicy设置为true,这会导致在取消时立即从工作队列中删除任务。

当您命令执行程序停止时,它会设置中断的标志,如果它是ScheduledThreadPoolExecutor,则在removeOnCancelPolicy为真时删除任务。

解决方案:

  • 在提交时间表之前执行executor.setRemoveOnCancelPolicy(true)

[编辑]: 由于您使用的是工厂方法,因此无法直接实现。

进行以下更改:

  • private final ScheduledThreadPoolExecutor executor;
  • executor = new ScheduledThreadPoolExecutor(1, (runnable) -> {