当前位置: 首页 > news >正文

JVM 终止机制详解:用户线程与守护线程

用户线程未执行完是否会阻止 JVM 终止?答案是:取决于线程类型。让我详细解释:

核心规则

JVM终止条件
所有用户线程结束
JVM终止
JVM继续运行
守护线程自动终止

线程类型与JVM终止关系

线程类型是否阻止JVM终止创建方式典型用途
用户线程✅ 是Thread t = new Thread();
t.setDaemon(false)
主线程、业务逻辑线程
守护线程❌ 否Thread t = new Thread();
t.setDaemon(true)
日志、监控、GC等后台任务

在您的日志系统中的体现

1. 日志处理器线程 (守护线程)

private PerfLogHandler() {Thread logProcessor = new Thread(this::processLogs, "perf-log-processor");logProcessor.setDaemon(true); // 设置为守护线程logProcessor.start();
}
  • 不会阻止JVM终止:当所有用户线程结束时自动终止
  • 可能丢失日志:JVM退出时未处理的队列日志会被丢弃

2. 线程池中的线程 (默认用户线程)

private final ThreadPoolExecutor logExecutor = new ThreadPoolExecutor(// ...new NamedThreadFactory("perf-log") // 默认创建用户线程
);

在您的 NamedThreadFactory 中:

public Thread newThread(Runnable r) {return new Thread(r, namePrefix + "-thread-" + threadNumber.getAndIncrement());// 默认是非守护线程(用户线程)
}

这里存在严重问题:这些线程会阻止JVM终止!

解决方案:优雅关闭

1. 修改线程工厂(创建守护线程)

private static class NamedThreadFactory implements ThreadFactory {@Overridepublic Thread newThread(Runnable r) {Thread t = new Thread(r, namePrefix + "-thread-" + threadNumber.getAndIncrement());t.setDaemon(true); // 关键修改!return t;}
}

2. 添加JVM关闭钩子(推荐)

private PerfLogHandler() {// 原初始化代码...// 添加关闭钩子Runtime.getRuntime().addShutdownHook(new Thread(() -> {shutdown();}));
}public void shutdown() {// 第一步:停止接收新日志logExecutor.shutdown();try {// 第二步:等待现有任务完成(最多10秒)if (!logExecutor.awaitTermination(10, TimeUnit.SECONDS)) {// 第三步:强制取消未完成任务List<Runnable> skipped = logExecutor.shutdownNow();log.warn("Forced shutdown, skipped {} logs", skipped.size());}// 第四步:处理队列剩余日志List<String> remaining = new ArrayList<>();logQueue.drainTo(remaining);if (!remaining.isEmpty()) {log.info("Processing {} remaining logs", remaining.size());new LogBatchTask(remaining).run();}} catch (InterruptedException e) {Thread.currentThread().interrupt();}
}

完整生命周期示例

用户线程JVM日志守护线程启动应用启动守护线程添加日志到队列执行业务逻辑所有用户线程结束发送中断信号处理剩余日志线程终止退出用户线程JVM日志守护线程

关键注意事项

  1. 守护线程使用原则

    • 只用于非关键后台任务
    • 必须能随时安全终止
    • 不能持有需要关闭的资源(如数据库连接)
  2. 用户线程阻塞场景

    public static void main(String[] args) {new Thread(() -> {while(true) { // 无限循环将阻止JVM退出}}).start();
    }
    
  3. 最佳实践

    • 后台服务线程设为守护线程
    • 使用ExecutorService替代裸线程
    • 总是实现优雅关闭逻辑
    • 监控线程状态:
      ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
      long[] ids = threadBean.getAllThreadIds();
      for (long id : ids) {ThreadInfo info = threadBean.getThreadInfo(id);System.out.println(info.getThreadName() + " is daemon: " + info.isDaemon());
      }
      

结论

在您的日志系统中:

  • 日志处理线程(守护线程)不会阻止JVM终止
  • 线程池工作线程(默认用户线程)会阻止JVM终止
  • 必须将线程池线程设为守护线程或实现优雅关闭

正确配置后,当所有业务线程(用户线程)结束时:

  1. JVM会终止所有守护线程
  2. 日志系统自动关闭
  3. JVM正常退出
http://www.lryc.cn/news/613151.html

相关文章:

  • WD6208资料和引脚图
  • MCU中的晶振(Crystal Oscillator)
  • 时间戳表示
  • 汽车娱乐信息系统域控制器的网络安全开发方案
  • 基于Ruby的IP池系统构建分布式爬虫架构
  • 基于 MATLAB 的 QPSK 调制、解调、通过高斯信道的误码率计算,并绘制误码率图和眼图、星座图
  • SurgRIPE 挑战赛:手术机器人器械位姿估计基准测试|文献速递-医学影像算法文献分享
  • 【源码】AndroidPlayer
  • 智能升级新纪元:基于Deepoc具身模型外拓开发板的除草机器人认知进化
  • 【图文教程】三步用Cpolar+JuiceSSH实现手机远程连接内网Linux虚拟机
  • Web开发模式 前端渲染 后端渲染 身份认证
  • 网页前端CSS实现表格3行平均分配高度,或者用div Flexbox布局
  • 网络安全等级保护(等保)2.0 概述
  • 深入理解Apache Camel:原理剖析与实践指南
  • 安全合规2--网络安全等级保护2.0介绍
  • 【Apache Olingo】全面深入分析报告-OData
  • 首个!3D空间推理框架3D-R1:融合强化学习、推理链、动态视角,实现7大任务SOTA!
  • ubuntu22.04安装docker
  • 基于 HT 引擎实现 3D 智慧物流转运中心一体化管控系统
  • 手写数字识别实战 - 从传统机器学习到深度学习
  • Spring AOP动态代理核心原理深度解析 - 图解+实战揭秘Java代理设计模式
  • 【驱动】RK3576-Debian系统使用ping报错:socket operation not permitted
  • 【ee类保研面试】数学类---概率论
  • c++编译环境安装(gcc、cmake)
  • 【C++】哈希表原理与实现详解
  • Numpy科学计算与数据分析:Numpy数学函数入门与实践
  • [激光原理与应用-172]:测量仪器 - 能量(焦耳)与功率(瓦)的图示比较
  • 此芯p1开发板使用OpenHarmony时llama.cpp不同优化速度对比(GPU vs CPU)
  • JavaWeb03——基础标签及样式(表单)(黑马视频笔记)
  • 【运维进阶】NFS 服务器