调用 run() 不会启动新线程,仅执行普通方法;真正创建并调度线程的是 start(),它调用 JVM 底层 C++ 函数(如 Linux 的 pthread_create、Windows 的 CreateThread)完成 OS 线程绑定与管理。

直接调用 run() 不会启动新线程,只是普通方法执行
这是最常踩的坑:把 Thread 对象创建好后,手快写了 t.run(),结果逻辑跑在主线程里,还纳闷“为什么没并发”。run() 本质就是一个普通实例方法,JVM 不做任何线程调度干预,它和你写个 doWork() 没区别。
真正触发线程创建和调度的是 start() —— 它内部会调用 JVM 的本地方法,最终走到 HotSpot 的 C++ 实现(比如 os::create_thread()),申请栈空间、注册到线程列表、交由 OS 调度器管理。
-
start()只能调用一次,重复调用抛IllegalThreadStateException -
run()可以反复调用,但永远不新开线程 - 如果你重写了
run()却忘了调用start(),那线程对象就只是个“待机状态”的空壳
start() 底层到底调了哪些 C++ 函数?
HotSpot 源码里,Thread::start() Java 方法最终映射到 JVM_StartThread,再进入 java_lang_Thread::start(),核心是调用 os::create_thread()。这个函数在不同平台实现不同:
- Linux 上走
pthread_create(),设置栈大小、分离状态等参数 - Windows 上用
CreateThread(),并注册异常处理回调 - 关键点:JVM 会为每个 Java 线程维护一个
osthread结构体,和 OS 线程 ID 绑定,后续所有 suspend/resume/interrupt 都依赖它
所以别幻想“绕过 start() 自己用 JNI 调 pthread_create()”,那样 JVM 完全不知道这个线程的存在,GC 不会扫描它的栈,Thread.currentThread() 拿不到它,interrupt() 更是无效。
立即学习“Java免费学习笔记(深入)”;
为什么不能在 run() 里手动调用 start()?
这个问题看似荒谬,但实际出现在某些动态代理或 AOP 场景中:比如想让 run() 执行前先做些初始化,结果误在 run() 里又调了一次 start()。
-
start()内部会检查线程状态是否为NEW,一旦进入RUNNABLE或其他状态,立刻抛异常 - 而
run()被调用时,线程早已不是NEW状态(哪怕你调的是t.run(),t的状态也还是NEW;但如果是t.start()后再进run(),状态已是RUNNABLE) - 更隐蔽的问题:如果在
run()中 new 一个新Thread并start()它,那是合法的——但容易造成线程爆炸,尤其在循环或回调里没控制数量
Runnable 和 Thread 的选择影响底层行为吗?
不影响。无论是继承 Thread 还是实现 Runnable,最终都通过 Thread(target).start() 进入同一套 C++ 流程。区别只在 Java 层的封装方式:
- 继承
Thread:run()是重写父类方法,this就是线程对象 - 实现
Runnable:Thread构造时把Runnable存进target字段,run()方法里判断if (target != null) target.run(); - 所以
Thread类本身其实是个“执行器”,不是“任务”——这点从它的run()方法源码就能看出
真正决定底层行为的是 start() 调用时机和线程生命周期管理,不是你用哪种方式组织代码。别被“继承 vs 组合”的设计讨论带偏,JVM 只认 start() 这一个入口。
线程状态切换、栈帧分配、本地线程存储(TLS)绑定,这些事 JVM 全包了,但前提是走 start() 这条路。漏掉这一步,后面所有并发语义都不成立。










