在关闭java程序前完成某些操作(释放资源,处理内存中的数据等)

优雅的关闭JAVA程序

背景

在线上Java程序中经常遇到进程程挂掉,一些状态没有正确的保存下来,这时候就需要在JVM关掉的时候执行一些清理现场的代码。Java中得ShutdownHook提供了比较好的方案。
  JDK在1.3之后提供了Java Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子,这个钩子可以在以下几种场景被调用:

  1. 程序正常退出
  2. 使用System.exit()
  3. 终端使用Ctrl+C触发的中断
  4. 系统关闭
  5. 使用Kill pid命令干掉进程
    注:在使用kill -9 pid是不会JVM注册的钩子不会被调用。

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

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

如何使用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")));

测试代码

public class ShutDownHook {

        public static void main(String[] args) {
            Runtime.getRuntime().addShutdownHook(new Thread()
            {
                @Override
                public void run()
                {

                    System.out.println("Interrupting threads");
                    Set<Thread> runningThreads = Thread.getAllStackTraces().keySet();
                    for (Thread runningThread : runningThreads) {
                        // 判断线程是否是我们要测试的线程
                        if (runningThread.getName().equals("InteruptThread")) {
                            // 如果线程没有被中断,我们进行中断他
                            if (!runningThread.isInterrupted()) {
                                System.out.println("InteruptThread is not interrupted, we are going to interupt it");
                                runningThread.interrupt();
                            }
                        }
                    }

                    System.out.println("Shutdown hook ran!");
                }
            });

            // 创建并启动子线程类
            InteruptThread thread = new InteruptThread();
            thread.start();
        }

        /**
         * 用来测试要中断的线程类
         */
        static class InteruptThread extends Thread {

            public InteruptThread() {
                this.setName("InteruptThread");
            }

            @Override
            public void run() {
                while (true) {
                    try {
                        while (true) {
                            // 打印个时间
                            System.out.println(System.currentTimeMillis());
                            // 等待10秒
                            TimeUnit.SECONDS.sleep(10);
                        }
                    } catch (InterruptedException e) {
                        System.out.println("oh yeah, InteruptThread is interrupted");
                        break;
                    } catch (Exception e) {
                        System.out.println("unknown exception ocurred");
                        break;
                    }

                }

            }
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章