Java线程创建与启动必须调用start()而非run():start()校验状态、加入线程组、调用native start0(),后者经JVM触发操作系统(如pthread_create)创建内核线程并调度执行run()。

Java 中线程的创建与启动,核心落在 Thread.start() 方法及其背后 JVM 的协作机制上。不是调用 run() 就算启动线程,而是必须走 start() → JVM → 操作系统内核这一整条链路,才能真正诞生一个可被调度的、独立的 OS 线程。
start() 方法做了什么?
调用 start() 是启动线程的唯一合法入口。它的关键行为包括:
- 校验线程状态:若 threadStatus ≠ 0(比如已启动或已终止),直接抛出 IllegalThreadStateException
- 将当前 Thread 实例加入所属线程组(
group.add(this)),便于统一管理 - 触发本地方法 start0() —— 这是真正的分水岭,它不写在 Java 层,由 JVM 用 C/C++ 实现
start0() 到底干了啥?
start0() 是 JVM 内部的 native 方法,其典型实现路径为:
- JVM 调用
JVM_StartThread(HotSpot 中) - 最终映射到操作系统 API,如 Linux 下调用
pthread_create() - 操作系统分配内核栈、寄存器上下文、TID,并将该线程纳入调度队列
- 新线程启动后,自动执行
Thread.run()—— 注意:这个 run() 是在新线程上下文中执行的,不是原线程里调用
run() 方法为什么不能直接调用?
Thread 类中的 run() 是一个普通实例方法,源码逻辑很清晰:
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
立即学习“Java免费学习笔记(深入)”;
- 如果构造时传入了 Runnable target(例如
new Thread(runnable)),就执行target.run() - 否则,执行子类重写的 run()(继承 Thread 方式)
但直接调用 thread.run() 只是在当前线程同步执行一段代码,**不会创建新线程,也不触发任何 OS 级资源分配** —— 它和普通方法调用没有任何区别。
线程对象与任务对象的解耦设计
从 Thread 构造方法源码可见:private Runnable target; 是核心字段。这解释了为何 Runnable 方式更主流:
- Thread 类只负责“执行载体”(调度、生命周期、OS 映射)
- Runnable / Callable 才是“业务逻辑”,可复用、可组合、不绑定线程实现
- FutureTask 就是 Runnable + Callable 的桥梁:它实现了 Runnable,又封装了 Callable 的 call() 和返回值获取能力
整个链条本质是:Java 层定义任务 → Thread 封装调度意图 → start() 触发 JVM 协作 → JVM 调用 OS 创建内核线程 → OS 回调 Java 执行 run()。抓住 start0() 这个 native 边界,就抓住了 Java 多线程落地的真正支点。

















