为什么 ExecutorService 接口没有实现 AutoCloseable?
Why does the ExecutorService interface not implement AutoCloseable?
未能在线程执行器上调用 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,因为该服务没有单个 "close" 类操作;但是两个!
如果您认为可以充分利用这种自动关闭服务,使用 "delegation" 编写您自己的实现将是 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
语句之间放置任何内容,也不能在 try
语句之后使用 service
局部变量。
鉴于注意事项,请改用 finally
。
我看不出 AutoCloseable 对 Executor 有什么用处。 try-with-resources 适用于可以在方法范围内初始化、使用和释放的事物。这非常适用于文件、网络连接、jdbc 资源等,它们可以快速打开、使用和清理。但是执行器,尤其是线程池,是你希望在很长一段时间内可用的东西,可能在应用程序的整个生命周期内,并且往往会被注入到诸如单例服务之类的东西中,它可以有一个 DI 框架知道的方法调用应用程序关闭以清理执行程序。这种使用模式在没有 try-with-resources 的情况下工作正常。
此外,try-with-resources 背后的一大动力是确保异常不会被掩盖。对于执行者来说,这不是一个考虑因素,所有的异常抛出都将发生在提交给执行者的任务中,
异常屏蔽不是问题。
In Java 19 EA ExeuctorService
now implements AutoCloseable
.
默认实现调用 shutdown()
并等待 awaitTermination
完成任务(1 天)。如果中断,它会调用 shutdownNow()
。
到那时,您可以使用Guava's 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();
}
}
}
}
未能在线程执行器上调用 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,因为该服务没有单个 "close" 类操作;但是两个!
如果您认为可以充分利用这种自动关闭服务,使用 "delegation" 编写您自己的实现将是 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
语句之间放置任何内容,也不能在 try
语句之后使用 service
局部变量。
鉴于注意事项,请改用 finally
。
我看不出 AutoCloseable 对 Executor 有什么用处。 try-with-resources 适用于可以在方法范围内初始化、使用和释放的事物。这非常适用于文件、网络连接、jdbc 资源等,它们可以快速打开、使用和清理。但是执行器,尤其是线程池,是你希望在很长一段时间内可用的东西,可能在应用程序的整个生命周期内,并且往往会被注入到诸如单例服务之类的东西中,它可以有一个 DI 框架知道的方法调用应用程序关闭以清理执行程序。这种使用模式在没有 try-with-resources 的情况下工作正常。
此外,try-with-resources 背后的一大动力是确保异常不会被掩盖。对于执行者来说,这不是一个考虑因素,所有的异常抛出都将发生在提交给执行者的任务中, 异常屏蔽不是问题。
In Java 19 EA ExeuctorService
now implements AutoCloseable
.
默认实现调用 shutdown()
并等待 awaitTermination
完成任务(1 天)。如果中断,它会调用 shutdownNow()
。
到那时,您可以使用Guava's 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();
}
}
}
}