• Runtime.addShutdownHook用法


    一、什么是ShutdownHook?

    在Java程序中可以通过添加关闭钩子,实现在程序退出时关闭资源、平滑退出的功能。 
    使用Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子,这个钩子可以在以下几种场景被调用: 
    1. 程序正常退出 
    2. 使用System.exit() 
    3. 终端使用Ctrl+C触发的中断 
    4. 系统关闭 
    5. 使用Kill pid命令干掉进程


    Runtime.java中相关方法源码

    public void addShutdownHook(Thread hook) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new RuntimePermission("shutdownHooks"));
        }
        ApplicationShutdownHooks.add(hook);
    }
    
    public boolean removeShutdownHook(Thread hook) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new RuntimePermission("shutdownHooks"));
        }
        return ApplicationShutdownHooks.remove(hook);
    }

    ApplicationShutdownHooks.java

    class ApplicationShutdownHooks {
        /* The set of registered hooks */
        private static IdentityHashMap<Thread, Thread> hooks;
        static {
            try {
                Shutdown.add(1 /* shutdown hook invocation order */,
                    false /* not registered if shutdown in progress */,
                    new Runnable() {
                        public void run() {
                            runHooks();
                        }
                    }
                );
                hooks = new IdentityHashMap<>();
            } catch (IllegalStateException e) {
                // application shutdown hooks cannot be added if
                // shutdown is in progress.
                hooks = null;
            }
        }
    
    
        private ApplicationShutdownHooks() {}
    
        /* Add a new shutdown hook.  Checks the shutdown state and the hook itself,
         * but does not do any security checks.
         */
        static synchronized void add(Thread hook) {
            if(hooks == null)
                throw new IllegalStateException("Shutdown in progress");
    
            if (hook.isAlive())
                throw new IllegalArgumentException("Hook already running");
    
            if (hooks.containsKey(hook))
                throw new IllegalArgumentException("Hook previously registered");
    
            hooks.put(hook, hook);
        }
    
        /* Remove a previously-registered hook.  Like the add method, this method
         * does not do any security checks.
         */
        static synchronized boolean remove(Thread hook) {
            if(hooks == null)
                throw new IllegalStateException("Shutdown in progress");
    
            if (hook == null)
                throw new NullPointerException();
    
            return hooks.remove(hook) != null;
        }
    
        /* 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) {
                try {
                    hook.join();
                } catch (InterruptedException x) { }
            }
        }
    }

    二、java进程平滑退出的意义

    很多时候,我们会有这样的一些场景,比如说nginx反向代理若干个负载均衡的web容器,又或者微服务架构中存在的若干个服务节点,需要进行无间断的升级发布。 
    在重启服务的时候,除非我们去变更nginx的配置,否则重启很可能会导致正在执行的线程突然中断,本来应该要完成的事情只完成了一半,并且调用方出现错误警告。 
    如果能有一种简单的方式,能够让进程在退出时能执行完当前正在执行的任务,并且让服务的调用方将新的请求定向到其他负载节点,这将会很有意义。 
    自己注册ShutdownHook可以帮助我们实现java进程的平滑退出。


    三、java进程平滑退出的思路

      1. 在服务启动时注册自己的ShutdownHook
      2. ShutdownHook在被运行时,首先不接收新的请求,或者告诉调用方重定向到其他节点
      3. 等待当前的执行线程运行完毕,如果五秒后仍在运行,则强制退出
  • 相关阅读:
    UNIX网络编程——Socket通信原理和实践
    UNIX环境高级编程——单实例的守护进程
    UNIX环境高级编程——初始化一个守护进程
    UNIX环境高级编程——创建孤儿进程
    UNIX环境高级编程——实现uid to name
    CentOS7中使用yum安装Nginx的方法
    centos7配置IP地址
    关于Dubbo的原理以及详细配置
    关于Java大数操作(BigInteger、BigDecimal)
    关于JSON 与 对象 、集合之间的转换
  • 原文地址:https://www.cnblogs.com/sunshisonghit/p/7683612.html
Copyright © 2020-2023  润新知