java中start()方法通过synchronized修饰、threadgroup锁保护及native层原子操作三重机制保障线程启动安全:先校验new状态防重复启动,再加锁注册线程,最后原子切换状态,而run()执行不在此同步范围内。

Java 中 start() 方法触发线程启动,表面看是一次方法调用,背后却依赖一套严谨的同步保障机制——它不是靠用户代码加锁实现的,而是由 JVM 在底层通过状态检查、临界区保护和 native 层原子操作共同完成的。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
start() 方法自身是 synchronized 的
Thread 类中 start() 是一个 synchronized 实例方法,这意味着:
- 同一 Thread 对象上并发调用多次
start()会被串行化,最多只有一个线程能真正进入方法体 - 它天然防止了“重复启动”问题:方法开头就检查
threadStatus != 0(即非 NEW 状态),若已启动或终止,直接抛出IllegalThreadStateException - 这种同步不依赖用户干预,是 JVM 强制施加的线程安全契约
线程注册过程受 ThreadGroup 锁保护
在 start() 内部,调用 group.add(this) 将新线程加入所属线程组。这个操作发生在 Threads_lock 这一 JVM 全局互斥锁的保护下(见 OpenJDK 实现):
- 确保多线程同时创建大量 Thread 实例时,线程组成员列表不会出现竞态或数据错乱
- 避免线程 ID 分配冲突、统计信息(如未启动计数)失真等问题
- 该锁也用于后续线程生命周期管理(如 stop、destroy、interrupt 等),是 JVM 线程基础设施的核心同步点
start0() 调用前后的状态切换是原子的
start0() 是 native 方法,但它前后被包裹在 try-finally 块中,并配合 started 标志位:
- 如果
start0()抛异常(如系统资源不足),JVM 会回调group.threadStartFailed(this)清理残留状态 - 整个流程保证:要么线程成功注册并进入 RUNNABLE 状态,要么彻底回滚,不留半初始化对象
- 这种“全有或全无”的语义,本质上是一种应用层的原子性保障,依赖 JVM 对 native 层失败的精确捕获与响应
run() 执行不在 start() 同步范围内
需要特别注意:start() 只负责把线程置为 RUNNABLE 并交由 OS 调度;run() 方法实际执行是在新线程上下文中发生的,与原调用线程完全解耦:
- 主线程调用
t.start()返回后,run()可能尚未执行,也可能正在执行,甚至已结束——这取决于 OS 调度时机 - 因此,
run()内部若需共享数据,必须另行同步(如 synchronized、volatile、Lock 或原子类),不能依赖start()的同步逻辑 - 这也是为什么直接调用
run()不触发任何线程安全机制——它只是普通方法调用,不涉及状态变更或资源注册
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










