• 利用JVM钩子函数优雅关闭线程池


    一、如何优雅关闭线程池

    核心API:

    • shutDown
    • shutDownNow
    • awaitTermination

    利用JVM钩子函数,在虚拟机关闭时调用相关方法即”优雅关闭线程池”。

    先通过shutdown等待线程池自身结束,然后等待一段时间,如果没有成功,再调用shutdownNow将等待I/O的任务中断并退出。

    
        /**
         * 添加钩子函数
         */
        private void initGracefullyShutDown() {
            Runtime.getRuntime().addShutdownHook(new Thread(() -> shutDownThreadPool(asyncExecutor, "BASE")));
            aliasExecutors.forEach((alias, threadPoolExecutor) ->
                    Runtime.getRuntime().addShutdownHook(new Thread(() -> shutDownThreadPool(threadPoolExecutor, alias)))
            );
        }
    
        /**
        * 优雅关闭线程池。
        *  自身关闭,await 60s,强制关闭。
        */
        private void shutDownThreadPool(ExecutorService threadPool, String alias) {
            log.info("Start to shutdown the thead pool : {}", alias);
    
            threadPool.shutdown();
            try {
                if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
                    threadPool.shutdownNow();
                    log.warn("Interrupt the worker, which may cause some task inconsistent");
    
                    if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
                        log.warn("Thread pool can't be shutdown even with interrupting worker threads, which may cause some task inconsistent.");
                    }
                }
            } catch (InterruptedException ie) {
                threadPool.shutdownNow();
                log.warn("The current server thread is interrupted when it is trying to stop the worker threads. This may leave an inconsistent state.");
    
                Thread.currentThread().interrupt();
            }
        }
    

    备注:本来是循环调用shutDownThreadPool()方法, 后来发现阻塞严重,追了下源码修改成了循环添加钩子了,具体看如下。

    二、其他

    JVM钩子函数

    执行时机

    自身没有细追源码,简单看了几篇其他伙伴记录的博客。

    • 虚拟机退出 :JVM会在所有非守护(后台)线程关闭后才会退出 (关于守护线程,随便看了几篇博客回忆下,这篇还不错。《大白话讲解守护线程》)
    • 系统调用System.exit(0)
    • JVM正常退出(Linux上kill命令也会调用钩子函数)

    追了一下源码,看了下,发现是一个集合维护Threads。(即咱们调用API,add进去的)

    ApplicationShutdownHooks.java

        /* Iterates over all application hooks creating a new thread for each
         * to run in. Hooks are run concurrently and this method waits for
         * them to finish.
         */
        static void runHooks() {
            Collection<Thread> threads;
            synchronized(ApplicationShutdownHooks.class) {
                threads = hooks.keySet();
                hooks = null;
            }
    
            for (Thread hook : threads) {
                hook.start();
            }
            for (Thread hook : threads) {
                while (true) {
                    try {
                        hook.join();
                        break;
                    } catch (InterruptedException ignored) {
                    }
                }
            }
        }
    }
    

    参考 《可伸缩服务架构 框架与中间件》
    参考 JVM的钩子函数实践调用

  • 相关阅读:
    TCPUDPSocket调试工具v2.2
    C#高性能Socket服务器IOCP实现
    c#使用HttpListener监听HTTP请求
    Winform Socket通信
    C# 方法中的this参数(扩展方法)
    C# 两种方法实现HTTP协议迷你服务器
    C#访问HTTP请求
    Socket通信原理
    C#数据decimal保留两位小数
    单机网站架构云化后架构图
  • 原文地址:https://www.cnblogs.com/deepSleeping/p/14976815.html
Copyright © 2020-2023  润新知