要判断线程是否真正并行执行,需检查run()未被synchronized修饰、主线程在start()后调用join()再getMax()、CPU多核利用率上升且总耗时显著降低,并通过jstack确认多线程处于RUNNABLE状态执行循环而非阻塞等待。
直接看线程是否真正并行执行——如果所有子任务串着跑,那并发就白写了。
检查 run() 方法有没有被 synchronized 修饰
这是最典型的“假多线程”错误。Java 中 Thread.run() 是普通方法,加 synchronized 不会让它变安全,只会让所有线程排队执行,彻底失去并发性。
- 错误写法:
public synchronized void run() { ... }→ 所有 MaxTask 实例共用同一个锁(this),强制串行 - 正确写法:
public void run() { ... }→ 各自独立运行,靠 join() 控制主线程等待,而非靠锁阻塞其他线程
确认主线程没在子线程启动后立刻读结果
如果主线程调用 getMax() 时子线程还没算完,拿到的只是初始值(比如 0),这不是数据竞争,而是时序失控。
- 必须在 start() 之后、getMax() 之前调用 join()
- 不能依赖 sleep() 或轮询;也不能把 getMax() 放在 run() 里返回——那是线程内局部行为,主线程看不到
观察 CPU 利用率和执行耗时
真并发下,多核 CPU 使用率应明显上升,且总耗时应显著低于单线程遍历(尤其数组很大时)。
- 如果 4 个线程分治,但总时间 ≈ 单线程时间,说明根本没并行
- 用 top -H(Linux)或任务管理器线程视图,确认多个线程处于 R(Running) 状态,而不是全卡在 S(Sleeping) 或 W(Waiting)
用 jstack 抓线程快照验证执行状态
运行中执行 jstack <pid>,查看子线程是否真的在执行循环逻辑,而不是堆在锁上或刚启动就结束了。
- 看到多个线程都停在
at java.lang.Thread.join(Native Method)→ 正常,主线程在等 - 看到多个线程都卡在
at java.lang.Object.wait(Native Method)且锁对象相同 → 很可能 run() 被 synchronized 锁住了 - 看到线程状态是 RUNNABLE 并正在执行你的 for 循环 → 并发正在发生

















