好问题!我认为您对awaitTermination() 方法没有清楚的了解。让我们看看这个document。
在关闭请求后阻塞,直到所有任务完成执行,或发生超时,或当前线程被中断,以先发生者为准。
awaitTermination() 不应用于等待所有任务完成。如果这是您正在寻找的语义,请使用invokeAll() 阻止直到所有任务完成。使用awaitTermination() 没有之前的shutdown() 是不正确的,并且可能由于awaitTermination 未关闭执行程序而导致您等待一段时间。
在这种情况下,您只是试图强制应用程序等待您的线程完成,但如果它不在您分配的时间范围内,您希望继续。这个具体案例让我对多线程的使用产生了一些疑问,因为它似乎有点过度设计,但出于教育目的,让我们解释一下如何做到这一点。
基本解决方案
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> foo());
// Thread.sleep(2000); // Wait for 2 seconds
TimeUnit.SECONDS.sleep(2); // Also waits for 2 seconds and a bit more readable
executor.submit(() -> bar());
if (!executor.awaitTermination(20, TimeUnit.SECONDS))
executor.shutdownNow();
虽然这不是理想的代码,但它会给你你正在寻找的语义。
改进
executor.submit() 将返回一个 Future<T> 对象。这是 Java 中非常强大的对象,具有很多功能。让我们看看我们如何改进这个场景。
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<T> foo = executor.submit(() -> foo());
T result = foo.get(2, TimeUnit.SECONDS); // Attempt to grab the result for 2 seconds, then move on
executor.submit(() -> bar());
if (!executor.awaitTermination(20, TimeUnit.SECONDS))
executor.shutdownNow();
现在,这是更合适的代码,并且会以更好的代码结构为您提供所需的语义。此外,如果第一个未来在 2 秒之前完成,它将提前解除阻塞,比基本解决方案有所改进!
正确关机
假设您想等待 20 秒以等待 executor 完成,您可以执行以下操作作为额外改进。使用以下代码进行关机,因为它来自ExecutorService 的文档作为关机示例。在这里,我已将您的等待时间更新为 20 秒。
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(20, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(20, 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();
}