jvm线程挂起采用协作式等待机制:安全点处理活跃线程,安全区域兜底休眠/阻塞线程;线程在预设安全点轮询全局标志并主动停靠,长循环中插入安全区域以避免stw延迟。

JVM 中线程挂起不是靠强制中断,而是靠协作式等待——安全点(Safepoint)处理“正在跑”的线程,安全区域(Safe Region)兜底“没法跑”的线程。
安全点:活跃线程的主动停靠站
当 JVM 需要 STW(如 GC 标记、jstack 采样),它不会立刻打断线程,而是设置一个全局标志(如 needs_gc)。所有 Java 线程在执行到预设的安全点位置时,会自动插入一条轻量轮询指令(例如汇编级 test %rax, [poll_page]),检查该标志。若为真,线程立即保存上下文,进入阻塞状态,等待 GC 完成。
- 安全点不是任意位置,而是 JIT 编译时选定的、状态确定的代码位置:方法返回前、循环末尾、异常抛出处、方法调用后
- 这些位置天然具备较长执行窗口,插入轮询几乎不增加额外开销;高频字节码(如 iload、iadd)则避开,避免性能损耗
- 关键在于:线程必须“走到”安全点才能响应,因此大循环若没插安全点,可能造成 STW 延迟——JVM 会在长循环中主动插入
安全区域:休眠/阻塞线程的免责区
线程处于 sleep、wait、blocked on monitor 或执行 JNI 本地方法 时,已交出 CPU 控制权,无法主动执行轮询指令,也就无法到达安全点。这时安全区域机制启动:
- 线程进入一段确认“引用关系不会变化”的代码前,标记自己为 in_safe_region = true
- JVM 发起 GC 时,直接跳过这些线程,不等待它们“醒来”
- 线程退出安全区域前,检查 GC 是否结束;若未结束,则阻塞等待,确保不会在 GC 过程中修改堆状态
两者配合实现无盲区同步
安全点覆盖运行态线程,安全区域覆盖非运行态线程,共同构成完整的 STW 协作框架:
- GC 触发后,JVM 等待所有线程:要么停在某个安全点,要么声明自己已在安全区域内
- 只有全部线程都就位(或声明安全),JVM 才正式开始枚举 GC Roots(依赖 OopMap)、执行标记等操作
- 整个过程不依赖抢占式中断,也不要求线程立即响应,而是基于契约与状态协商
不复杂但容易忽略











