java 关闭勾子的使用方法
1、最佳位置(main
方法起始处)
确保可靠性:即使后续代码抛出异常,关闭钩子已注册
避免竞态条件:防止在注册前就收到关闭信号
public class App { public static void main(String[] args) { // 1. 最先注册关闭钩子(确保一定能被执行) Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("正在关闭资源..."); PooledProducer.shutdown(); //这句是ActiveMQ关闭函数,就是个示例, //这里写程序关闭时需要执行的代码 })); //下面写业务逻辑代码
} }
2、关闭钩子的触发场景
触发方式 | 是否能执行关闭钩子 | 示例 |
---|---|---|
正常退出 | ✅ 能 | System.exit(0) |
Ctrl+C | ✅ 能 | 控制台中断 |
kill -15 | ✅ 能 | kill -15 <pid> |
kill -9 | ❌ 不能 | 强制杀死进程 |
JVM崩溃 | ❌ 不能 | OutOfMemoryError |
系统关机 | ✅ 能 | Linux shutdown -h now |
3、增强版实现(带超时控制)
Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("接收到关闭信号,开始优雅停止..."); long start = System.currentTimeMillis(); PooledProducer.shutdown(); // 关闭生产者 这句是示例,需要写 在程序关闭要执行的代码 // 等待线程池终止(最多10秒) try { if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { System.err.println("强制终止未完成任务"); executor.shutdownNow(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.printf("关闭完成,耗时 %dms%n", System.currentTimeMillis() - start); }));
注:避免死锁
不要在关闭钩子中执行耗时操作(如等待网络响应)
设置合理的超时时间(如10秒)