start()方法通过jmm的happens-before规则间接保障共享变量初始可见性:主线程start()前的写操作对新线程run()中首次读取可见,但不保证start()后的修改可见,需配合volatile或synchronized实现持续可见性与原子性。

Java 中 start() 方法本身不直接保证共享变量的可见性,但它触发了 Java 内存模型(JMM)中一条关键的 happens-before 规则,从而间接建立起主线程与新线程之间的内存可见性保障。
start() 启动线程时建立 happens-before 关系
根据 JMM 规范,主线程调用 t.start() 的操作,happens-before 新线程(t)中 run() 方法里的任意操作。这意味着:
- 主线程在
t.start()之前对共享变量所做的所有写入(包括初始化对象字段、赋值等),对新线程的首次读取都是可见的; - 该规则强制 JVM 在线程启动前,将主线程工作内存中已修改但尚未刷回主内存的变量,同步到主内存;同时要求新线程在执行
run()前,清空本地缓存,从主内存重新加载变量值; - 这本质上是一次“内存屏障”插入:在
start()调用处隐式插入了写屏障(store barrier),在新线程入口处插入了读屏障(load barrier)。
它能保证什么,又不能保证什么?
能保证:线程启动前已完成的初始化状态对新线程可见。例如:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
public class VisibilityExample {
static int x = 0;
static boolean flag = false;
public static void main(String[] args) throws InterruptedException {
x = 42; // 主线程写
flag = true; // 主线程写
Thread t = new Thread(() -> {
// 这里一定能看到 x == 42 且 flag == true
System.out.println(x + ", " + flag);
});
t.start(); // ← happens-before 关系在此确立
t.join();
}
}
不能保证:主线程在 start() 之后再修改的变量,对新线程自动可见。例如:
- 若主线程在
t.start()后才设置flag = true,而新线程未加同步就轮询flag,仍可能因缓存或重排序导致永远看不到更新(即典型可见性问题); - 该规则只作用于线程启动“那一刻”的内存状态快照,不提供持续的可见性保障。
与 volatile / synchronized 的配合关系
start() 提供的是单次、一次性的初始可见性,后续通信必须依赖其他同步机制:
- 若需持续观察共享状态变化(如轮询标志位),应使用
volatile修饰该变量,确保每次读都从主内存加载; - 若涉及复合操作(如“读-改-写”),必须用
synchronized或java.util.concurrent工具类,既保证原子性也强化可见性; -
start()和volatile可协同使用:前者确保初始值可见,后者确保运行时更新可见。
底层实现依赖操作系统线程创建语义
JVM 的 start() 最终委托给 OS 创建原生线程(如 pthread_create)。主流操作系统在线程创建时会保证:
- 新线程继承父线程当时的内存映射视图;
- 内核调度器确保新线程首次执行前,CPU 缓存(尤其是 store buffer 和 invalidation queue)已按内存一致性模型完成同步;
- 这种 OS 层面的保证,是 JVM 实现 happens-before 语义的物理基础。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










