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

线程池到底该怎么关闭

作者: 江江的大猪 | 来源:发表于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