如何正确关闭java ExecutorService

如何正确关闭java ExecutorService

我有一个简单的java ExecutorService运行一些任务对象(实现Callable)。


ExecutorService exec = Executors.newSingleThreadExecutor();

List<CallableTask> tasks = new ArrayList<>();

// ... create some tasks

for (CallableTask task : tasks) {

 Future future = exec.submit(task);

 result = (String) future.get(timeout, TimeUnit.SECONDS);

 // TASKS load some classes and invoke their methods (they may create additional threads)

 // ... catch interruptions and timeouts

}

exec.shutdownNow();

在完成所有任务(DONE或TIMEOUT-ed)之后,我尝试关闭执行程序,但它不会停止:exec.isTerminated() = FALSE. 我怀疑某些被执行的任务未正确终止。


是的,我知道执行者的关闭不能保证任何事情:


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


我的问题是,有没有办法确保这些(任务)线程终止?我提出的最佳解决方案是System.exit()在程序结束时调用,但这很简单。


凤凰求蛊
浏览 1753回答 2
2回答

胡说叔叔

从ExecutorService的&nbsp;Oracle API文档页面推荐的方法:&nbsp;void&nbsp;shutdownAndAwaitTermination(ExecutorService&nbsp;pool)&nbsp;{ &nbsp;&nbsp;&nbsp;pool.shutdown();&nbsp;//&nbsp;Disable&nbsp;new&nbsp;tasks&nbsp;from&nbsp;being&nbsp;submitted &nbsp;&nbsp;&nbsp;try&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Wait&nbsp;a&nbsp;while&nbsp;for&nbsp;existing&nbsp;tasks&nbsp;to&nbsp;terminate &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!pool.awaitTermination(60,&nbsp;TimeUnit.SECONDS))&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pool.shutdownNow();&nbsp;//&nbsp;Cancel&nbsp;currently&nbsp;executing&nbsp;tasks &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Wait&nbsp;a&nbsp;while&nbsp;for&nbsp;tasks&nbsp;to&nbsp;respond&nbsp;to&nbsp;being&nbsp;cancelled &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!pool.awaitTermination(60,&nbsp;TimeUnit.SECONDS)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.err.println("Pool&nbsp;did&nbsp;not&nbsp;terminate"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(InterruptedException&nbsp;ie)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;(Re-)Cancel&nbsp;if&nbsp;current&nbsp;thread&nbsp;also&nbsp;interrupted &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pool.shutdownNow(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Preserve&nbsp;interrupt&nbsp;status &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.currentThread().interrupt(); &nbsp;&nbsp;&nbsp;}如果您的池有更多时间关闭,您可以更改1f&nbsp;(!pool.awaitTermination(60,&nbsp;TimeUnit.SECONDS))至while&nbsp;(!pool.awaitTermination(60,&nbsp;TimeUnit.SECONDS))关闭相关方法的简要概述shutdown():启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务。shutdownNow():尝试停止所有正在执行的任务,停止等待任务的处理,并返回等待执行的任务列表。awaitTermination(long timeout,TimeUnit unit)抛出InterruptedException:阻止所有任务在关闭请求之后完成执行,或者发生超时,或者当前线程被中断,以先发生者为准。

慕尼黑的夜晚无繁华

你有控制这些任务吗?即你自己创造这些?我怀疑那些线程中断被忽略的地方,例如try&nbsp;{ &nbsp;&nbsp;....}catch&nbsp;{InterruptedException&nbsp;e)&nbsp;{ &nbsp;&nbsp;&nbsp;//&nbsp;do&nbsp;nothing}抛出InterruptedException时,需要重置线程上的中断标志,否则线程不会退出。见此处获得更多信息。不幸的是,您可能正在使用不遵守此规定的库,在这种情况下,您无法轻易绕过这一点。在这种情况下,一个重量级选项是分叉一个子进程来执行该作业Callable,这将在进程退出时清除所有资源。重量级的,可能是非平凡的,但可靠的。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java