ExecutorService 的 shutdown() 不会等到所有线程都完成
ExecutorService's shutdown() doesn't wait until all threads will be finished
我有一个代码,其中同时有 4 个线程 运行。我想等到所有这 4 个线程都完成。只有在那之后才能继续应用程序流程。
我尝试了两种方法:
Thread#join()
,此方法按预期工作。 join()
之后的代码仅在所有线程完成后执行。
ExecutorService#shutdown()
,即使并非所有线程都已完成,此技术也允许执行 shutdown()
之后的代码。
代码示例:
ExecutorService service = Executors.newFixedThreadPool(cpuCoresNum);
for (int i = 0; i < cpuCoresNum; i++) {
service.submit(() -> {
try {
foo(); // some long execution function
} catch (Exception e) {
e.printStackTrace();
}
});
}
service.shutdown();
System.out.println("We're done! All threads are finished!");
我的问题:
- 为什么
submit()
和 shutdown()
不等到所有线程都完成并打印 «我们完成了!所有线程都已完成!» 在 service.shutdown();
调用后立即结束?
答案可在 ExecutorService.shutdown()
Javadoc 中找到:
This method does not wait for previously submitted tasks to complete execution. Use awaitTermination
to do that.
如果您想等待线程完成工作,您有以下选择:
- 获取
submit()
返回的 Future
个实例并在每个 Future
个实例上调用 get()
- 在
service
上调用 shutdown
后,在 service
上调用 awaitTermination
直到 returns true
- 而不是在
service
上调用 submit
将您的 Runnable
实例添加到 java.util.List
并将此列表传递给在 [= 上调用的 invokeAll
方法17=]
感谢@Adam Siemion的建议,这里是最终代码:
ExecutorService service = Executors.newFixedThreadPool(cpuCoresNum);
int itNum = 1;
for (int i = 0; i < cpuCoresNum; i++) {
int treadID = itNum++;
service.submit(() -> {
Thread.currentThread().setName("Thread_#" + treadID);
try {
foo();
} catch (Exception e) {
e.printStackTrace();
}
});
}
// wait until all threads will be finished
service.shutdown();
try {
service.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
来自 ExecutorService 的 oracle 文档页面的推荐方法:
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();
}
shutdown():
启动有序关闭,执行之前提交的任务,但不会接受新任务。
shutdownNow():
尝试停止所有正在执行的任务,停止等待任务的处理,并returns列出等待执行的任务。
在上面的示例中,如果您的任务需要更多时间才能完成,您可以将 if 条件更改为 while 条件
替换
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
和
while(!pool.awaitTermination(60, TimeUnit.SECONDS)) {
Thread.sleep(60000);
}
我有一个代码,其中同时有 4 个线程 运行。我想等到所有这 4 个线程都完成。只有在那之后才能继续应用程序流程。
我尝试了两种方法:
Thread#join()
,此方法按预期工作。join()
之后的代码仅在所有线程完成后执行。ExecutorService#shutdown()
,即使并非所有线程都已完成,此技术也允许执行shutdown()
之后的代码。
代码示例:
ExecutorService service = Executors.newFixedThreadPool(cpuCoresNum);
for (int i = 0; i < cpuCoresNum; i++) {
service.submit(() -> {
try {
foo(); // some long execution function
} catch (Exception e) {
e.printStackTrace();
}
});
}
service.shutdown();
System.out.println("We're done! All threads are finished!");
我的问题:
- 为什么
submit()
和shutdown()
不等到所有线程都完成并打印 «我们完成了!所有线程都已完成!» 在service.shutdown();
调用后立即结束?
答案可在 ExecutorService.shutdown()
Javadoc 中找到:
This method does not wait for previously submitted tasks to complete execution. Use
awaitTermination
to do that.
如果您想等待线程完成工作,您有以下选择:
- 获取
submit()
返回的Future
个实例并在每个Future
个实例上调用get()
- 在
service
上调用shutdown
后,在service
上调用awaitTermination
直到 returnstrue
- 而不是在
service
上调用submit
将您的Runnable
实例添加到java.util.List
并将此列表传递给在 [= 上调用的invokeAll
方法17=]
感谢@Adam Siemion的建议,这里是最终代码:
ExecutorService service = Executors.newFixedThreadPool(cpuCoresNum);
int itNum = 1;
for (int i = 0; i < cpuCoresNum; i++) {
int treadID = itNum++;
service.submit(() -> {
Thread.currentThread().setName("Thread_#" + treadID);
try {
foo();
} catch (Exception e) {
e.printStackTrace();
}
});
}
// wait until all threads will be finished
service.shutdown();
try {
service.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
来自 ExecutorService 的 oracle 文档页面的推荐方法:
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();
}
shutdown():
启动有序关闭,执行之前提交的任务,但不会接受新任务。
shutdownNow():
尝试停止所有正在执行的任务,停止等待任务的处理,并returns列出等待执行的任务。
在上面的示例中,如果您的任务需要更多时间才能完成,您可以将 if 条件更改为 while 条件
替换
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
和
while(!pool.awaitTermination(60, TimeUnit.SECONDS)) {
Thread.sleep(60000);
}