c++oding="utf-8" ?>
start() 方法触发 jvm 创建真正的 os 线程,而非直接调用 run();其流程为:java 层校验状态并设为 runnable,jvm 通过 jvm_startthread → javathread::start_thread() → os::create_thread()(linux 下即 pthread_create)创建线程,再由 c++ thread_entry 初始化后调用 java 的 run()。
java 中的 start() 方法看似简单,但背后牵扯的是 java 层、jvm 运行时、线程调度和本地操作系统的一整套协作机制。它不是直接调用 run(),而是触发 jvm 启动一个真正的 os 线程——这个过程在 hotspot jvm 中由 c++ 实现,不暴露给 java 开发者,但理清它能帮你真正理解“多线程为何不能靠反复调用 run() 来实现”。
start() 不是执行 run(),而是注册并唤醒一个新线程
调用 Thread.start() 时,Java 层只是做了几件事:检查线程状态(必须是 NEW)、设置线程为 RUNNABLE 状态、把线程对象加入 JVM 的线程列表。真正的线程创建动作发生在 JVM 的本地方法 JVM_StartThread 中——这是个 JNI 函数,由 HotSpot 的 thread.cpp 实现。
- Java 层的
start()最终会跳转到JVM_StartThread(定义在src/hotspot/share/prims/jvm.cpp) - 该函数内部调用
JavaThread::start_thread(),后者封装了os::create_thread() -
os::create_thread()是平台相关实现,Linux 下本质是pthread_create调用
底层 C++ 线程入口不是 run(),而是 thread_entry
JVM 不会让 OS 线程直接执行你写的 run() 方法。它先启动一个统一的 C++ 入口函数 thread_entry(位于 src/hotspot/share/runtime/thread.cpp),再由这个函数完成 Java 栈初始化、JNI 环境绑定,最后才调用 Java 的 run()。
-
thread_entry接收的是JavaThread*指针,不是 Java 对象 - 它会调用
thread->run()(注意:这是 C++ 的JavaThread::run(),不是 Java 的Runnable.run()) - 这个 C++
run()再通过 JNI 调用目标线程对象的run()方法(即你重写的那个)
为什么重复调用 start() 会抛 IllegalThreadStateException?
因为 JVM 在 C++ 层维护了线程的生命周期状态机。一旦 os::create_thread() 成功返回,线程状态就从 NEW 变为 RUNNABLE;如果此时再调 start(),JVM_StartThread 会检测到状态非法,直接返回失败,Java 层捕获后抛出异常。
- 状态存储在
JavaThread对象的_thread_state字段中(枚举值如NEW、RUNNABLE、TERMINATED) - 这个字段在
os::create_thread()前被设为RUNNABLE,创建失败则回滚;成功后不可逆 - 所以哪怕线程已执行完
run()进入TERMINATED,也不能再次start()—— JVM 不允许复用线程对象
调试建议:想看 C++ 层发生了什么?
不需要编译整个 JVM。你可以:
- 下载 OpenJDK 源码(推荐 jdk8u 或 jdk17u),定位到
src/hotspot/share/prims/jvm.cpp查JVM_StartThread - 用
hsdis+java -XX:+PrintAssembly观察 JIT 编译后的本地代码(适合进阶) - 在 Linux 下用
strace -e trace=clone,pthread_create运行简单多线程程序,看到底层系统调用 - 加 JVM 参数
-XX:+PrintGCDetails -XX:+PrintGCDateStamps配合线程 dump(jstack)对比状态变化
理解 start() 的本地调用链,不是为了写 JNI,而是建立对“Java 线程即 OS 线程”这一事实的肌肉记忆。它解释了为何线程开销大、为何有数量限制、为何要谨慎使用线程池——这些都不是语言规范写的,而是藏在那几行 C++ 里。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











