未能在线程执行器上调用
shutdown()
将导致应用程序永远不会终止。
关闭 ExecutorService 的最佳实践是这样的:
ExecutorService service = null;
try {
service = Executors.newSingleThreadExecutor();
// add tasks to thread executor
…
} finally {
if (service != null) service.shutdown();
}
既然 Java 知道 try-with-resources 概念,如果我们能做到这一点不是很好吗?
try (service = Executors.newSingleThreadExecutor())
{
// add tasks to thread executor
…
}
ExecutorService实际上有两个与关闭相关的方法;基于一个简单的事实:两种关闭服务的方法都是有意义的。
因此:那么你将如何自动关闭服务呢?以一致的方式对每个人都有效?!所以,在我看来合理的解释是:你不能将 ExecutorService 设置为 AutoClosable,因为该服务没有单一的“关闭”之类的操作;但是两个!
如果你认为你可以很好地利用这样一个自动关闭服务,那么使用“委托”编写你自己的实现将是一个 5 分钟的事情!或者可能是 10 分钟,因为您将创建一个调用
shutdown()
作为关闭操作的版本;以及一个做
shutdownNow()
的人。
ExecutorService service = Executors.newSingleThreadExecutor();
try (Closeable close = service::shutdown) {
}
或者,如果受检查的异常困扰您,您可以写:
interface MyCloseable extends AutoCloseable {
void close();
}
然后
ExecutorService service = Executors.newSingleThreadExecutor();
try (MyCloseable close = service::shutdown) {
}
当然,您绝不能在赋值和
try
语句之间放置任何内容,也不能在
service
语句之后使用
try
局部变量。鉴于注意事项,只需使用
finally
即可。
ExecutorService
在 Java 19+ 中是
AutoCloseable
Java 19 开始,ExecutorService
实现了
AutoCloseable
。
默认实现调用 shutdown()
并在循环中使用
awaitTermination
等待任务完成。如果被中断,它会调用
shutdownNow()
。谷歌番石榴
Guava的ForwardingExecutorService
ExeuctorService
为
AutoCloseable
:
class CloseableExecutorService extends ForwardingExecutorService implements AutoCloseable {
private final ExecutorService delegate;
CloseableExecutorService(ExecutorService delegate) {
this.delegate = checkNotNull(delegate);
}
@Override
protected ExecutorService delegate() {
return delegate;
}
@Override
public void close() {
// copy paste from JDK 19 EA
boolean terminated = isTerminated();
if (!terminated) {
shutdown();
boolean interrupted = false;
while (!terminated) {
try {
terminated = awaitTermination(1L, TimeUnit.DAYS);
} catch (InterruptedException e) {
if (!interrupted) {
shutdownNow();
interrupted = true;
}
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
}
此外,try-with-resources 背后的一个重要动机是确保异常不会被掩盖。对于执行器来说,这不是一个需要考虑的问题,所有异常抛出都将发生在提交给执行器的任务中, 异常屏蔽不是问题。
try(ExecutorService executorService = Executors.newFixedThreadPool(10)){
//do stuff with you executor service
executorService.shutdown();
try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
log.warn("Shutting Down Executor forcefully .... ");
executorService.shutdownNow();
}
}catch (InterruptedException e) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
} finally {
log.info("----------FINISHED PROCESSING--------------");
}
}