Thread.start()只能调用一次,重复调用会抛IllegalThreadStateException;直接调用run()不会启动新线程,只是同步执行;start()后线程进入RUNNABLE状态但未必立即执行,需正确同步共享变量。

Thread.start() 为什么不能重复调用
调用 Thread.start() 后,线程状态从 NEW 变为 RUNNABLE(就绪),JVM 会将其加入调度队列等待 CPU 时间片。一旦进入 RUNNABLE 或后续状态(如 RUNNING、BLOCKED),再次调用 start() 就会抛出 IllegalThreadStateException —— 这不是 bug,是 JVM 的强制约束。
- 一个
Thread实例只能启动一次,无论它是否已执行完毕 - 想“重启”线程?必须新建
Thread对象,不能复用旧实例 - 常见误操作:在循环里反复对同一个
thread变量调用start(),结果第二轮就崩
run() 和 start() 混用导致线程没真正并发
直接调用 thread.run() 不会启动新线程,只是在当前线程同步执行 run() 方法体,和普通方法调用无异。这是新手最常踩的坑——代码看似用了多线程,实则仍是单线程串行。
- ✅ 正确:创建后调用
thread.start() - ❌ 错误:写成
thread.run(),或误把start()当作可重入入口 - 调试时可通过
Thread.currentThread().getName()打印线程名验证是否真切换了上下文
就绪状态不等于立即执行,别依赖“马上跑起来”
Thread.start() 返回时,线程已进入 RUNNABLE 状态,但未必立刻获得 CPU。它要排队等操作系统调度,可能被挂起几毫秒甚至更久——尤其在高负载或线程数远超 CPU 核心数时。
- 不要在
start()后立刻假设共享变量已被修改,需配合synchronized、volatile或CountDownLatch等做同步 - 避免用
Thread.sleep(10)“等线程启动”,这既不可靠也不可移植 - 如果需要确认某段逻辑已在新线程中开始执行,应在
run()内部发信号(比如设置 volatile 标志或 countDown)
子类继承 Thread 时,别忘了重写 run() 方法
继承 Thread 类后,若未重写 run(),默认实现是空的,start() 启动后啥也不干就结束了。这不是异常,是静默失败。
- 务必重写
public void run(),并把要并发执行的逻辑放进去 - 如果用
Runnable构造Thread(如new Thread(runnable).start()),确保传入的Runnable实例的run()已正确定义 - IDE 通常能提示未实现抽象方法,但手动 new Thread() + 匿名内部类时容易漏掉
线程就绪只是并发的第一步,真正难的是状态协同和资源可见性——哪怕 start() 成功返回,System.out.println("started") 在新线程里打印出来之前,主线程看到的共享变量值可能还是旧的。










