在项目中看到有用 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 关闭可以分为三种
- 正常关闭:当最后一个非守护线程结束或调用 System.exit() 或通过其他特定平台的特定方式关闭
- 强制关闭:通过调用 Runtime.halt() 或在操作系统中直接 kill JVM进程
- 异常关闭:运行时遇到 RuntimeException 异常等
JVM关闭时的使用场景
可以在关闭时执行一些清理临时文件,关闭资源,停止任务,停止其他服务等等操作。
关闭钩子
ShutdownHook hook直译即为钩子的意思
通过 Runtime.getRuntime().addShutdownHook() 添加到钩子列表的钩子在 JVM 关闭前会去执行这些钩子中的任务。
示例见 RunTIme 的一些使用最后一个
即在 JVM 关闭前的最后一些收尾操作,但是也需要注意一些使用事项
需要注意:
- 如果JVM因异常关闭,那么子线程(Hook本质上也是子线程)将不会停止。但在JVM被强行关闭时,这些线程都会被强行结束
- 关闭钩子本质上是一个线程(也称为Hook线程),用来监听JVM的关闭。通过使用 Runtime 的addShutdownHook(Thread hook) 可以向JVM注册一个关闭钩子
- Hook线程在JVM 正常关闭时才会执行,在强制关闭时不会执行
- 对于一个 JVM 中注册的多个关闭钩子它们将会并发执行,所以JVM并不能保证它的执行顺序
- 当所有 Hook线程执行完毕后,如果此时 runFinalizersOnExit(类内部定义的属性)为true,那么JVM将先运行终结器,然后停止
- Hook线程的执行当然会延迟 JVM 的关闭时间,这就要求在编写钩子过程中必须要尽可能减少Hook线程的执行时间
- 由于多个钩子是一起执行的,那么很可能因为代码不当导致出现竞态条件或死锁等问题,为了避免该问题,强烈建议在一个钩子中执行一系列操作
- 不能在钩子内调用 System.exit(),否则会卡住 JVM 的关闭过程,可以调用Runtime.halt() 替代
- 不能在钩子中再进行钩子的添加和删除操作,否则将会抛出 IllegalStateException 异常
- 在System.exit()之后添加的钩子无效
- 当JVM收到 SIGTERM 命令(比如操作系统在关闭时)后,如果钩子线程在一定时间没有完成,那么Hook线程可能在执行过程中被终止
- 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() {
// 要执行的操作
}
}));