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