Java 最优雅关闭线程池得两种方式

注册钩子函数

    private static void shutDownThreadPool(){
        Runtime.getRuntime().addShutdownHook( new ShutdownHookThread(log,() -> {
            poolExecuteConcurrentHashMap.forEach( (k,v) -> {
                if(Optional.ofNullable( v ).isPresent())
                    v.shutdown();
            } );
            return null;
        }) );
    }



    public class ShutdownHookThread extends Thread {
        private volatile boolean hasShutdown = false;
        private AtomicInteger shutdownTimes = new AtomicInteger(0);
        private final Logger log;
        private final Callable callback;

        public ShutdownHookThread(Logger log, Callable callback) {
            super("ShutdownHook");
            this.log = log;
            this.callback = callback;
        }

        @Override
        public void run() {
            synchronized (this) {
                log.info("shutdown hook was invoked, " + this.shutdownTimes.incrementAndGet() + " times.");
                if (!this.hasShutdown) {
                    this.hasShutdown = true;
                    long beginTime = System.currentTimeMillis();
                    try {
                        this.callback.call();
                    } catch (Exception e) {
                        log.error("shutdown hook callback invoked failure.", e);
                    }
                    long consumingTimeTotal = System.currentTimeMillis() - beginTime;
                    log.info("shutdown hook done, consuming time total(ms): " + consumingTimeTotal);
                }
            }
        }
    }

对于通过注册ShutdownHook实现的优雅退出,需要注意如下几点,防止踩坑

(1)ShutdownHook在某些情况下并不会被执行,例如JVM崩溃、无法接收信号量和kill-9 pid等。

(2)当存在多个ShutdownHook时,JVM无法保证它们的执行先后顺序。

(3)在JVM关闭期间不能动态添加或者去除ShutdownHook。

(4)不能在ShutdownHook中调用System.exit(),它会卡住JVM,导致进程无法退出。

信号量回调函数

    Signal signal = new Signal( System.getProperty( "os.name" ).toLowerCase().startsWith( "win" ) ? "INT" : "TERM" );
        Signal.handle( signal,signal1 -> {
            System.out.println("释放资源");
        } );

其中Signal构造函数的参数为String字符串,它代表了操作系统支持的信号量列表(此处注意:不同操作系统支持的信号量不同),如表1-1所示为Linux支持的一些常用信号量。

判断是否是Windows操作系统,如果是则选择SIGINT,接收Ctrl+C中断的指令,否则选择TERM信号,接收SIGTERM(等价于kill pid)指令(备注:这里仅是支持Windows和Linux操作系统的代码示例)。

将实例化之后的SignalHandler注册到JDK的Signal,一旦Java进程接收到killpid或Ctrl+C,则回调handle接口:

对于采用注册 SignalHandler 实现优雅退出的程序,在 handle 接口中一定要避免阻塞操作,否则它会导致已经注册的 ShutdownHook无法执行,系统也无法退出

猜你喜欢

转载自blog.csdn.net/wmq880204/article/details/115408498