主线程完成时优雅地关闭 ExecutorService

问题描述 投票:0回答:3

在实用程序库中,我正在创建一个 ExecutorService

ExecutorService es = Executors.newSingleThreadExecutor();

主线程随后会将一些任务发布到这个ExecutorService。当主线程完成时,我想关闭 ExecutorService 以允许应用程序退出。

问题是我只能更改实用程序库中的代码。我考虑的一种选择是使用守护线程。但随后它会在发布到服务的任务完成之前突然关闭。

java threadpool executorservice
3个回答
6
投票

使用

Runtime#addShutdownHook()
将关闭钩子添加到当前运行时。

例如

Runtime.getRuntime().addShutdownHook(new Thread() {
    public void run() {
        es.shutdown();
        try {
            es.awaitTermination(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            logger.info("during await",e);
        }
    }
});

在构建/初始化实用程序类时执行此操作。


3
投票
除非您将执行器设置为守护线程,否则

shutdownHook
将不起作用。原因在这里

shutdownhook
当 JVM 开始退出时启动,除非你调用
es.shutDown()
,否则 JVM 不会退出,所以它是一个死锁。

我不知道为什么制作守护进程执行器不起作用。它应该。守护进程执行器在主类启动的所有线程完成执行之前不会关闭(除非它们也是守护进程)

创建执行器时尝试此代码

   ExecutorService es = Executors.newSingleThreadExecutor( new ThreadFactory() {
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setDaemon(true);
            return t;
        }
    });

0
投票
final ExecutorService executor;

Runtime.getRuntime().addShutdownHook(new Thread() {
    public void run() {
        executor.shutdown();
        try {
            if (!executor.awaitTermination(SHUTDOWN_TIME, TimeUnit.SECONDS)) {
                // Optional: Log that the executor still had tasks to process after waiting the specified time.
                Logger.log("Executor did not terminate within the specified time.");

                // Optional: Attempt to forcefully terminate the executor's worker threads.
                List<Runnable> droppedTasks = executor.shutdownNow();
                Logger.log("Executor was abruptly shut down. " + droppedTasks.size() + " tasks will not be executed.");
            }
        } catch (InterruptedException e) {
            // Handle interruption while waiting for termination (if needed).
        }
    }
});

注:

  • awaitTermination 方法与可选超时一起使用来等待 以便有序终止任务。
  • 可选日志语句提供有关终止的信息 状态以及任何可能未完成的任务。
  • 调用shutdownNow方法强制终止 执行器的工作线程,以及有关该执行器的日志信息 删除了任务。

此外,值得注意的是,当处理 Java 进程的中断或 ExecutorService 仅由守护线程组成时,此解决方案非常有效。如果非守护线程存在且尚未完成,JVM 可能不会尝试关闭,因此不会调用关闭挂钩。在这种情况下,如果关闭是离散应用程序生命周期的一部分,则关闭代码应放置在程序设计终止的适当位置,而不是放置在关闭挂钩内。

© www.soinside.com 2019 - 2024. All rights reserved.