直接调用run()不会创建新线程,仅在当前线程同步执行,丧失并发性;start()才真正启动新线程,由jvm调度执行run()方法,实现异步并发。

直接调用 run() 不会报错,但线程逻辑会在当前线程串行执行,完全失去并发意义——这是多线程 bug 中最隐蔽、最常被忽略的问题之一。关键不是“有没有异常”,而是“有没有真正的新线程”。
看线程名:最快速的现场验证
在 run() 方法第一行加一句:
System.out.println("当前线程名:" + Thread.currentThread().getName());
然后对比调用方式:
- 如果调用的是
thread.start(),输出通常是Thread-0、Thread-1等新线程名; - 如果误写成
thread.run(),输出一定是main(或你当前所在的线程名),说明根本没启新线程。
查线程数量:运行时确认是否多线程生效
在启动逻辑前后插入线程计数检查:
System.out.println("启动前线程数:" + Thread.activeCount());<br>thread.start(); // 或误写的 run()<br>System.out.println("启动后线程数:" + Thread.activeCount());
正常调用 start() 后,线程数应增加 1(或更多,取决于 JVM 状态);而 run() 调用前后线程数不变。
观察执行顺序和并发行为
设计一个简单可观察的并发测试:
- 让子线程 sleep 500ms 后打印 “done”;
- 主线程在
start()或run()调用后立刻打印 “main continues”; - 若看到 “main continues” 先输出、“done” 后输出 → 很可能是
start(),并发发生; - 若总是 “done” 先输出、“main continues” 后输出 → 极大概率是
run(),纯同步执行。
静态检查:代码扫描习惯性风险点
以下写法需立即审查:
-
new Thread(() -> {...}).run();—— 典型错误,新建了对象却没启动; -
myThread.run();(而上下文本该是myThread.start()); - 在单元测试中反复调用
run()模拟线程,却忘了真实环境必须用start()。
IDE 中可配置 inspection:搜索 .run\(\) 调用,再人工确认调用者是否为 Thread 实例且上下文明确需要并发。










