JVM关闭与关闭钩子 Runtime.getRuntime().addShutdownHook() 作用以及相关注意事项

在项目中看到有用 Runtime.getRuntime().addShutdownHook() ,位置处于线程池的初始化后的最后处理, Runtime.getRuntime().addShutdownHook() 中添加了线程的shutdown() 以及 awaitTermination() 用于关闭线程池的资源

例如:

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
      try {
              executor.shutdown();
              executor.awaitTermination(WAIT_TIME, TimeUnit.SECONDS);
              executor = null;
          } catch (InterruptedException e) {
              LOGGER.error("..........", e);
          }
      }));

executor为在上面声明为线程池

JVM 关闭

三种方式

JVM 关闭可以分为三种

  1. 正常关闭:当最后一个非守护线程结束或调用 System.exit() 或通过其他特定平台的特定方式关闭
  2. 强制关闭:通过调用 Runtime.halt() 或在操作系统中直接 kill JVM进程
  3. 异常关闭:运行时遇到 RuntimeException 异常等
JVM关闭时的使用场景

可以在关闭时执行一些清理临时文件,关闭资源,停止任务,停止其他服务等等操作。

关闭钩子

ShutdownHook hook直译即为钩子的意思
通过 Runtime.getRuntime().addShutdownHook() 添加到钩子列表的钩子在 JVM 关闭前会去执行这些钩子中的任务。
示例见 RunTIme 的一些使用最后一个
即在 JVM 关闭前的最后一些收尾操作,但是也需要注意一些使用事项

需要注意

  1. 如果JVM因异常关闭,那么子线程(Hook本质上也是子线程)将不会停止。但在JVM被强行关闭时,这些线程都会被强行结束
  2. 关闭钩子本质上是一个线程(也称为Hook线程),用来监听JVM的关闭。通过使用 Runtime 的addShutdownHook(Thread hook) 可以向JVM注册一个关闭钩子
  3. Hook线程在JVM 正常关闭时才会执行,在强制关闭时不会执行
  4. 对于一个 JVM 中注册的多个关闭钩子它们将会并发执行,所以JVM并不能保证它的执行顺序
  5. 当所有 Hook线程执行完毕后,如果此时 runFinalizersOnExit(类内部定义的属性)为true,那么JVM将先运行终结器,然后停止
  6. Hook线程的执行当然会延迟 JVM 的关闭时间,这就要求在编写钩子过程中必须要尽可能减少Hook线程的执行时间
  7. 由于多个钩子是一起执行的,那么很可能因为代码不当导致出现竞态条件或死锁等问题,为了避免该问题,强烈建议在一个钩子中执行一系列操作
  8. 不能在钩子内调用 System.exit(),否则会卡住 JVM 的关闭过程,可以调用Runtime.halt() 替代
  9. 不能在钩子中再进行钩子的添加和删除操作,否则将会抛出 IllegalStateException 异常
  10. 在System.exit()之后添加的钩子无效
  11. 当JVM收到 SIGTERM 命令(比如操作系统在关闭时)后,如果钩子线程在一定时间没有完成,那么Hook线程可能在执行过程中被终止
  12. Hook 线程中同样会抛出异常,如果抛出异常不处理,那么钩子的执行序列就会被停止

RunTime 的一些使用

内存计算

获取当前运行环境的实例对象

Runtime runtime = Runtime.getRuntime();

返回Java虚拟机中的内存总量。此方法返回的值可能随时间变化,具体取决于主机环境。

runtime.totalMemory();

返回Java虚拟机中的可用内存量。调用 gc 方法可能会导致返回的值增加空闲内存。

runtime.freeMemory();

返回Java虚拟机将尝试使用的最大内存量。如果没有固有限制,则返回值

java.lang.Long#MAX_value

runtime.maxMemory()

由此我们便可以计算出此时的内存占用率
即:

double rate = (runtime.totalMemory() - runtime.freeMemory()) / runtime.maxMemory();

这个数值在 0 到 1 之间 乘以百分百得到占用百分比。

同样的可以手动调用 gc() 执行回收机制。

执行命令 process
		Runtime runtime = Runtime.getRuntime();
        Process process = null;
        try {
            process = runtime.exec("要执行的命令");
        } catch (Exception e){
            e.printStackTrace();
        }
runTime 添加 addShutdownHook 例子

lambda 方式

	Runtime.getRuntime().addShutdownHook(new Thread(() -> {
        try {
        // 要执行的操作
             .........
         } catch (Exception e) {
            ................
         }
     }));

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
    @Override
        public void run() {
            // 要执行的操作
        }
    }));
参考文章链接

RunTime.getRunTime().addShutdownHook
深入JVM关闭与关闭钩子

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值