简体   繁体   English

如何正确关闭java ExecutorService

[英]How to properly shutdown java ExecutorService

I have a simple java ExecutorService that runs some task objects (implements Callable ).我有一个简单的 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();

After all tasks are finished (either DONE or TIMEOUT-ed), I try to shutdown the executor, but it wont stop: exec.isTerminated() = FALSE.在所有任务完成后(完成或超时),我尝试关闭执行程序,但它不会停止: exec.isTerminated() = FALSE. I suspect that some tasks that are timeouted are not properly terminated.我怀疑某些超时的任务没有正确终止。

And yes, I know that executor's shutdown is not guaranteing anything:是的,我知道 executor 的关闭并不能保证任何事情:

There are no guarantees beyond best-effort attempts to stop processing actively executing tasks.除了尽力尝试停止处理正在执行的任务之外,没有任何保证。 For example, typical implementations will cancel via {@link Thread#interrupt}, so any task that fails to respond to interrupts may never terminate.例如,典型的实现将通过 {@link Thread#interrupt} 取消,因此任何未能响应中断的任务可能永远不会终止。

My question is, is there a way to ensure those (task) threads will terminate?我的问题是,有没有办法确保那些(任务)线程会终止? The best solution I came up with, is to call the System.exit() at the end of my program, but that is plain silly.我想出的最佳解决方案是在程序结束时调用System.exit() ,但这很愚蠢。

Recommended way from Oracle API documentation page of ExecutorService :来自ExecutorService 的Oracle API 文档页面的推荐方式:

 void shutdownAndAwaitTermination(ExecutorService pool) {
   pool.shutdown(); // Disable new tasks from being submitted
   try {
     // Wait a while for existing tasks to terminate
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
       pool.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     }
   } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     pool.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();
   }

If your pool is taking more time to shutdown, you can change如果您的池需要更多时间关闭,您可以更改

if (!pool.awaitTermination(60, TimeUnit.SECONDS))

to

while (!pool.awaitTermination(60, TimeUnit.SECONDS))

A brief summary of the shutdown related methods关机相关方法的简单总结

shutdown() : 关机()

Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.启动有序关闭,其中执行先前提交的任务,但不会接受新任务。

shutdownNow() : 关机现在()

Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.尝试停止所有正在执行的任务,停止等待任务的处理,并返回等待执行的任务列表。

awaitTermination(long timeout, TimeUnit unit) throws InterruptedException : awaitTermination(long timeout, TimeUnit unit) 抛出 InterruptedException

Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.阻塞直到所有任务在关闭请求后完成执行,或发生超时,或当前线程被中断,以先发生者为准。

Do you have control of those tasks ?你能控制这些任务吗? ie are you creating those yourself ?即你自己创造那些? I suspect somewhere in those a thread interrupt is being ignored eg我怀疑其中某个线程中断被忽略,例如

try {
  ....
}
catch {InterruptedException e) {
   // do nothing
}

When an InterruptedException is thrown, the interrupt flag on the thread needs to be reset, otherwise the thread will not exit.当抛出 InterruptedException 时,需要重置线程上的中断标志,否则线程不会退出。 See here for more info .请参阅此处了解更多信息

Unfortunately you may be using a library that doesn't obey this, in which case you can't easily circumvent this.不幸的是,您可能正在使用不遵守此规定的库,在这种情况下,您无法轻松规避这一点。 In that case one heavyweight option is to fork off a sub process to perform the job of the Callable , and that will clear up all resources upon process exit.在这种情况下,一个重量级的选择是派生一个子进程来执行Callable的工作,这将在进程退出时清除所有资源。 Heavyweight and possibly non-trivial, but reliable.重量级,可能不平凡,但可靠。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM