美文网首页
线程池到底该怎么关闭

线程池到底该怎么关闭

作者: 江江的大猪 | 来源:发表于2020-04-25 21:49 被阅读0次
  • 工作这几年见到的所有工程的线程池基本上都是只管使用,不管关闭,虽然大部分都没什么问题,因为大多数关闭脚本中会有服务下线和等待时间,但是这样仅仅是绕开了问题,并不代表问题不存在
  • 首先线程池如果想要确保正确关闭,要从三个方向考虑。第一个是线程是不是守护线程、第二个是线程池是否还可以接收任务、第三个是怎么知道线程池把任务都执行完了
  • 上述第一点对应的是线程池中的ThreadFactory,其中会设置线程池中的线程是否是守护线程。第二点对应的是线程池的shutDown方法,执行过后调用sumbit或execute会被拒绝。第三点对应的是线程池的awaitTermination方法,如果线程池中的任务都执行完了则返回true否则false
  • 所以可以如下做,如果线程池中的任务还没执行完jvm就不关闭
    // 真正的工程不该使用Executors中快捷方法创建的线程池,这里只是演示作用
    private static ExecutorService executorService = Executors.newCachedThreadPool();
    static {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            executorService.shutdown();
            try {
                while (!executorService.awaitTermination(1, TimeUnit.SECONDS)) {
                    System.out.println("还没执行完");
                }
            } catch (InterruptedException e) {
                // 忽略,执行这段逻辑的是jvm关闭的钩子线程,不用考虑中断问题
            }
        }));
    }
  • 因为现实场景中,一个任务的执行时间一定是有一个上线的,所以我们可以使用guava提供的快捷方法处理线程池的关闭问题,默认最长等待120秒,可以设置
//getExitingExecutorService会把线程池中的线程都改为守护线程,并且在jvm关闭时的钩子线程中执行shutDown和awaitTermination
//awaitTermination方法返回只有,不论线程池中的任务执没执行完,因为钩子线程已经执行完了,此时jvm中应该只剩下线程池的守护线程,所以这些守护线程也就随着jvm的关闭结束了
MoreExecutors.getExitingExecutorService(new ThreadPoolExecutor(5, 5, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10)))
  • guava源码关键部分展开如下:
        executor.setThreadFactory(new ThreadFactoryBuilder()
                .setDaemon(true)
                .setThreadFactory(executor.getThreadFactory())
                .build());
        addShutdownHook(MoreExecutors.newThread("DelayedShutdownHook-for-" + service, new Runnable() {
            @Override
            public void run() {
                try {
                    // We'd like to log progress and failures that may arise in the
                    // following code, but unfortunately the behavior of logging
                    // is undefined in shutdown hooks.
                    // This is because the logging code installs a shutdown hook of its
                    // own. See Cleaner class inside {@link LogManager}.
                    service.shutdown();
                    service.awaitTermination(terminationTimeout, timeUnit);
                } catch (InterruptedException ignored) {
                    // We're shutting down anyway, so just ignore.
                }
            }
        }));

相关文章

网友评论

      本文标题:线程池到底该怎么关闭

      本文链接:https://www.haomeiwen.com/subject/dgjlwhtx.html