Java垃圾回收暂停线程依靠安全点和安全区域协作机制:运行中线程在安全点主动检查并挂起,阻塞线程在安全区域标记后无需等待,退出时再检查,确保GC Roots准确且对象引用关系不被破坏。

Java 垃圾回收时暂停所有应用线程,靠的不是“强行中断”,而是线程主动协作停靠——核心机制就是 安全点(Safepoint) 和 安全区域(Safe Region)。它们共同确保:JVM 能在不破坏对象引用关系、不丢失 GC Roots、不误删存活对象的前提下,让所有 Java 线程统一进入暂停状态。
安全点:线程运行中“可停车”的协作位置
安全点是 JIT 编译器在生成机器码时,插入的检查点。线程只有执行到这些位置,才会主动查看 JVM 是否发出了“请暂停”的信号(通过轮询一个全局 volatile 标志位)。常见安全点位置包括:
- 方法调用前(尤其是调用另一个 Java 方法时)
- 方法返回前(栈帧即将弹出,局部变量表完整稳定)
- 循环回边(for/while 循环末尾的跳转处)
- 异常抛出后(异常处理表入口)
- 解释执行中字节码分发器隐式检查点
关键在于:线程不会被突然打断。它会继续跑,直到下一个安全点,再检查是否需要挂起。这样能保证此时寄存器已刷新、栈帧结构清晰、所有对象引用关系可准确枚举——GC 就能安全扫描 GC Roots。
若代码中存在长循环且无方法调用(如 while(true) { i++; }),JIT 可能省略安全点插入,导致该线程迟迟不响应,拖长 STW 时间。解决方式是手动引入轻量调用,例如 Thread.onSpinWait() 或 System.nanoTime(),触发隐式安全点检查。
立即学习“Java免费学习笔记(深入)”;
安全区域:线程“不跑了”,也得管住它
安全点只覆盖“正在运行”的线程。但线程可能处于 sleep、wait、park、IO 阻塞、synchronized 锁等待 等状态——此时它不执行 Java 字节码,无法轮询安全点标志位。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
安全区域就是为这类情况设计的:一段代码逻辑明确、**引用关系绝不会变化**的区间。线程进入该区域时,会标记自己“已进入安全区域”;JVM 发起 GC 时,就无需等待它到达安全点,可直接开始根节点枚举等操作。
当线程准备离开安全区域(比如从 Object.wait() 返回、从 LockSupport.park() 唤醒),它必须检查 JVM 是否已完成 STW 阶段:
- 如果已完成,线程继续执行
- 如果尚未完成,线程必须阻塞等待,直到收到“可离开”信号
典型的安全区域包括:进入 Object.wait()、Thread.sleep()、LockSupport.park() 的瞬间,以及 JNI 调用进入 native 方法前(但 native 返回 Java 时,必须立即检查一次安全点)。
暂停过程:主动式中断 + 协作等待
JVM 不采用“抢占式中断”(即强制发信号打断线程),因为那会导致上下文混乱、寄存器状态不可知。现代 HotSpot 全部使用主动式中断:
- JVM 设置一个全局中断请求标志(如
SafepointSynchronize::is_synchronizing()) - 所有 Java 线程定期在安全点轮询该标志
- 处于运行态的线程走到下一个安全点即挂起
- 处于安全区域的线程,在退出时检查并可能等待
- JNI 线程虽不轮询,但从 native 返回 Java 时强制检查一次
整个过程完成后,所有 Java 线程统一静止,GC 才真正开始标记、清理或压缩——这就是 Stop-The-World 的实质:一次可控、协作、状态一致的全局暂停。

















