java 为什么ExecutorService接口不实现AutoCloseable?

wlzqhblo  于 2023-04-04  发布在  Java
关注(0)|答案(4)|浏览(194)

如果在线程执行器上调用shutdown()失败,将导致应用程序永远不会终止。
关闭ExecutorService的最佳做法是:

ExecutorService service = null;
try {
  service = Executors.newSingleThreadExecutor();
  // add tasks to thread executor
  …
} finally {
  if (service != null) service.shutdown();
}

既然Java知道资源尝试的概念,如果我们能做到这一点,那不是很好吗?

try (service = Executors.newSingleThreadExecutor())
{
  // add tasks to thread executor
  …
}
3wabscal

3wabscal1#

那个ExecutorService其实有两个关机相关的方法;基于一个简单的事实,即关闭服务的两种方式都有意义。
因此:你将如何自动关闭一个服务呢?以一种对每个人都有效的一致方式?!
所以,我眼中的合理解释:你不能使ExecutorService成为AutoClosable,因为该服务没有一个类似“close”的操作;而是两个!
如果你认为你可以很好地利用这样一个自动关闭服务,那么使用“委托”编写你自己的实现将是一件5分钟的事情!或者可能是10分钟,因为你将创建一个调用shutdown()作为关闭操作的版本;一个是shutdownNow()

yxyvkwin

yxyvkwin2#

这是一个平庸的变通方法

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即可。

h7wcgrx3

h7wcgrx33#

ExeuctorService是Java 19+中的AutoCloseable

在Java 19中,ExeuctorService现在实现了AutoCloseable
默认实现调用shutdown()并等待awaitTermination完成任务(1天)。如果中断,则调用shutdownNow()

谷歌Guava

对于早期的Java,您可以使用Guava's ForwardingExecutorServiceExeuctorService装饰为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();
      }
    }
  }
}
6yjfywim

6yjfywim4#

我看不出AutoCloseable对Executor有什么用。try-with-resources是用于可以在方法范围内初始化,使用和释放的东西。这对于文件,网络连接,jdbc资源等非常有用,它们可以快速打开,使用和清理。但是Executor,特别是线程池,是你想要长时间可用的东西。可能在应用程序的生命周期内,并且倾向于注入到诸如单例服务之类的东西中,这些服务可以有一个方法,DI框架知道在应用程序关闭时调用该方法来清理执行器。这种使用模式在没有尝试资源的情况下工作得很好。
另外,try-with-resources背后的一个重要动机是确保异常不会被屏蔽。这不是执行器需要考虑的问题,所有的异常抛出都将发生在提交给执行器的任务中,异常屏蔽不是问题。

相关问题