繁体   English   中英

为什么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,因为该服务没有类似“关闭”的操作; 但是两个!

如果你认为你可以很好地利用这种自动关闭服务,那么使用“委托”编写你自己的实现将是 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 背后的一大动力是确保异常不会被掩盖。 对于执行者来说,这不是一个考虑因素,所有的异常抛出都将发生在提交给执行者的任务中,异常屏蔽不是问题。

在 Java 19 中,EA ExeuctorService现在实现了AutoCloseable

默认实现调用shutdown()并使用awaitTermination等待任务完成(1 天)。 如果中断,它会调用shutdownNow()


在此之前,您可以使用Guava 的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();
      }
    }
  }
}

Try-with-resources是关于Readers / Streams的自动关闭,其中ExecutorService是关于使用线程池执行任务的。

所以我不确定两者之间是否存在并行关系,我们可以考虑将try-with-resources应用于ExecutorServices。

更新
引用Java语言规范:

try-with-resources语句使用变量(称为资源)进行参数化,这些变量在执行try块之前初始化并在执行try块后以与它们初始化的相反顺序自动关闭。 当资源自动关闭时,通常不需要catch子句和finally子句。

规范将变量称为“资源” 所以我不确定是否可以将ExecutorService作为资源调用,因此不要将ExecutorService视为与Readers / Streams / Statement / ResultSet / Connection等并行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM