zoukankan      html  css  js  c++  java
  • 【从零单排】Java关闭钩子的应用

    背景

    在开发中,遇到这种情况,多个线程同时工作,突然一个线程遇到了fetal的错误,需要立即终止程序,等人工排查解决了问题之后重新启动。但是这样会有一个问题,程序终止时,其他线程可能正在进行重要操作,比如发一个message到另一个模块,并更新数据库状态。突然终止,可能会让这个操作只完成一半,从而导致数据不一致。

    解决方案是:参考数据库Transaction原子性的概念,将这一系列重要操作看作一个整体,要么全部完成,要么全部不完成。为方便表述,我们把这一系列重要操作记为操作X。
    当程序即将退出时,查看当前是否有操作X在执行中,

    • 如果有,等待其完成然后退出。且期间不再接受新的操作X。如果操作X执行之间过长,终止并回滚所有状态。
    • 如果没有,则可以立即退出。

    在程序退出的时候,做一些Check,保证已经开始的操作X的原子性,这里就用到了Runtime.ShutdownHook

    什么是Shutdown Hook

    Shutdown hook是一个initialized but unstarted thread。当JVM开始执行shutdown sequence时,会并发运行所有registered Shutdown Hook。这时,在Shutdown Hook这个线程里定义的操作便会开始执行。

    需要注意的是,在Shutdown Hook里执行的操作应当是不太耗时的。因为在用户注销或者操作系统关机导致的JVM shutdown的例子中,系统只会预留有限的时间给未完成的工作,超时之后还是会强制关闭。

    什么时候会调用Shutdown Hook

    • 程序正常停止
      • Reach the end of program
      • System.exit
    • 程序异常退出
      • NPE
      • OutOfMemory
    • 受到外界影响停止
      • Ctrl+C
      • 用户注销或者关机

    如何使用Shutdown Hook

    调用java.lang.Runtime这个类的addShutdownHook(Thread hook)方法即可注册一个Shutdown Hook,然后在Thread中定义需要在system exit时进行的操作。如下:

    Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("Do something in Shutdown Hook")));
    

    测试例子

    首先,注册了一个Shutdown Hook
    然后,系统Sleep 3秒,模拟进行某些操作。
    然后,调用一个空的List,抛出异常,准备结束程序。
    在程序将要结束的时候,执行Shutdown Hook中的内容。

    public static void main(String[] args)
    {
        // register shutdown hook
        Runtime.getRuntime().addShutdownHook(new Thread(() -> System.out.println("Do something in Shutdown Hook")));
    
        // sleep for some time
        try {
            for (int i=0; i<3; i++) {
                System.out.println("Count: " + i + "...");
                TimeUnit.MILLISECONDS.sleep(1000);
            }
            List nullList = new ArrayList<>();
            System.out.println("Trying to print null list's first element: " + nullList.get(0).toString());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    
        System.out.println("Ready to exit.");
        System.exit(0);
    }
    

    结果如下:

    Count: 0...
    Count: 1...
    Count: 2...
    Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    	at java.util.ArrayList.rangeCheck(ArrayList.java:653)
    	at java.util.ArrayList.get(ArrayList.java:429)
    	at HookTest.main(HookTest.java:18)
    Do something in Shutdown Hook
    
    Process finished with exit code 1
    

    需要注意的点

    • System.exit之后,当Shutdown Hook开始执行时,其他的线程还是会继续执行。
    • 应当保证Shutdown Hook的线程安全。
    • 在使用多个Shutdown Hook时一定要特别小心,保证其调用的服务不会被其他Hook影响。否则会出现当前Hook所依赖的服务被另外一个Hook终止了的情况。

    链接

  • 相关阅读:
    Python入门之面向对象的多态
    Python入门之面向对象的多态和继承
    Python入门之面向对象之类继承与派生
    Python入门之logging模块
    Python入门之字符编码
    Python入门之软件开发目录规范
    Python入门之ATM+购物车代码版思维导图
    mysql distinct
    Mysql中关于 group_concat函数详解
    关于mysql函数GROUP_CONCAT
  • 原文地址:https://www.cnblogs.com/maxstack/p/9112711.html
Copyright © 2011-2022 走看看