必须调用start()启动线程,run()只是普通方法,直接调用不会创建新线程;start()校验状态、注册线程并调用native start0()使线程进入runnable态,之后jvm在新线程中自动执行run()。

因为 run() 方法本身不负责创建线程,它只是个普通方法,执行逻辑全在当前线程里跑,没有底层系统资源分配和调度介入。
run() 是纯业务逻辑入口,不是线程启动器
无论你继承 Thread 还是实现 Runnable,重写的 run() 方法都只定义“要做什么”,而不是“在哪做”或“怎么启动”。JVM 不会因为这个方法存在就自动开辟新栈、分配 CPU 时间片或注册到线程调度器。
- 它就像 main() 方法一样,本质是被调用的代码块
- 直接调用 thread.run(),等价于写了一段 for 循环或打印语句,完全同步执行
- 此时 Thread.currentThread().getName() 一定还是 "main",说明没脱离主线程上下文
start() 才触发真正的线程生命周期管理
start() 方法内部做了三件关键事:校验线程状态、加入线程组、调用本地方法 start0()。这个 native 方法由 JVM 实现,会向操作系统申请资源,创建独立的执行栈和寄存器上下文。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 只有 start() 调用后,线程才从 NEW 状态进入 RUNNABLE(就绪),等待被调度
- start0() 成功返回后,JVM 自动在新线程中回调你的 run() 方法
- 重复调用 start() 会抛 IllegalThreadStateException,因为状态不可逆
直接调用 run() 的实际表现
它不会报错,但行为完全不符合多线程预期:
- 所有任务串行执行,CPU 利用率不会提升
- 无法体现并发效果,比如两个 thread.run() 总是先执行完第一个再执行第二个
- 如果 run() 里有 sleep 或 I/O,主线程会被阻塞,UI 或服务响应会卡住
- 调试时看到的线程名、堆栈帧全属于主线程,毫无“新线程”痕迹
为什么设计成这样?
这是 Java 显式区分“定义任务”和“调度执行”的设计哲学:
- run() 聚焦任务内容,可复用、可测试、无副作用
- start() 封装系统级操作,避免用户误触底层资源
- 把线程创建权交给 JVM 和 OS,保证安全性和跨平台一致性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










