调用start()抛IllegalThreadStateException是因为线程状态已非NEW;start()触发新线程调度,run()仅为普通方法调用;应通过getState()==NEW判断是否可启动,禁用isAlive()替代,终止后不可重启,需新建Thread或使用ExecutorService。

为什么调用 start() 会抛 IllegalThreadStateException
线程对象一旦启动过(即 start() 成功返回),其内部状态就从 NEW 变为 RUNNABLE 或后续状态,此时再调用 start() 必然失败。JVM 明确禁止重复启动,不是 bug,是设计约束。
常见错误现象:
- 误把
run()当成启动方法,手动调用后又调start() - 在多线程环境下未加锁或未判状态,多个地方尝试
start() - 线程已自然结束(
TERMINATED),仍试图重启——Java 不支持线程复用
start() 和 run() 的本质区别
这是最常混淆的点:start() 是 JVM 协作入口,触发新线程调度;run() 只是普通方法调用,仍在当前线程执行,不改变线程状态。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 永远不要手动调用
run()来“模拟启动”,它不会创建新线程,也不会让线程进入RUNNABLE - 调试时若想验证逻辑,可单独提取
run()内容到普通方法,避免误触状态机 - 检查堆栈里是否出现
at MyThread.run(MyThread.java:...)被直接调用的痕迹
如何安全判断线程是否可启动
不能靠捕获 IllegalThreadStateException 来做流程控制——异常是信号,不是分支逻辑。正确做法是查询状态。
可用的判断方式:
- 用
thread.getState() == Thread.State.NEW精确判断:只有该状态下才允许start() - 避免用
thread.isAlive()替代:它对NEW和TERMINATED都返回false,无法区分“没启过”和“已结束” - 如果业务需要“确保只启动一次”,推荐用
AtomicBoolean做标记,比反复查状态更可靠
线程终止后还能做什么
一旦线程进入 TERMINATED 状态,它就彻底死亡,不能再 start(),也不能重置状态。这时候能做的只有:
- 读取它的执行结果(如果用了
Future或共享变量) - 丢弃引用,等待 GC
- 新建一个
Thread实例来执行相同任务——这才是正确的“重启”方式
注意:频繁创建线程代价高,生产环境应优先考虑 ExecutorService 复用工作线程,而不是反复 new + start。
真正容易被忽略的是:线程对象本身不是资源容器,它的生命周期和状态不可逆。别把它当可重置的工具类用。








