illegalthreadstateexception在java中因对非new状态线程重复调用start()而抛出;线程仅在new状态可启动,一旦进入runnable、terminated等状态再调用即失败。

IllegalThreadStateException 是 Java 中的运行时异常,当线程处于不允许执行某操作的状态时抛出。其中最典型的情况是:对一个已经调用过 start() 方法的线程,再次调用 start()。
线程状态机是核心判断依据
Java 线程生命周期由 Thread.State 枚举定义,start() 方法只允许在线程处于 NEW 状态时成功执行。一旦进入 RUNNABLE(含就绪/运行中)、BLOCKED、WAITING、TIMED_WAITING 或 TERMINATED 中任一状态,再次调用 start() 就会触发 IllegalThreadStateException。
关键逻辑分支如下:
- 线程对象刚创建,未调用
start()→ 状态为NEW→ 允许调用start() - 线程已调用
start(),且尚未终止 → 状态变为RUNNABLE或其它非NEW状态 → 再次调用start()→ JVM 检查状态失败 → 抛出异常 - 线程已运行完毕(自然结束或被中断)→ 状态为
TERMINATED→ 此时再调用start()同样非法 → 抛出异常
start() 方法内部状态校验逻辑
在 OpenJDK 源码中,Thread.start() 会先调用 checkAccess(),再执行关键判断:
if (threadStatus != 0) // 0 表示 NEW 状态
throw new IllegalThreadStateException();
这里的 threadStatus 是由 JVM 维护的底层状态字段,其值为 0 仅在新建线程且未启动时成立。一旦 JVM 完成线程调度初始化(如分配栈、注册到线程列表),该值立即更新,后续任何 start() 调用都会因非零值而失败。
常见误用场景与规避方式
开发者容易在循环、重试逻辑或状态管理不清晰时重复调用 start(),例如:
- 将
Thread对象缓存复用,错误地认为“线程结束就能重启” - 在监听回调中未加状态判断,每次事件都尝试
start() - 使用匿名线程且未保存引用,误以为新建了线程对象(实际可能复用了变量)
正确做法:
- 每个线程对象只能启动一次;需要多次执行任务,请改用
ExecutorService提交Runnable/Callable - 若需感知线程是否存活,可用
isAlive()判断,但不能据此调用start() - 避免手动管理线程生命周期;优先使用线程池、
ForkJoinPool或现代并发工具类
调试与定位建议
遇到该异常时,应重点检查:
- 异常堆栈中
start()的调用位置,确认是否在多处或条件分支中被重复触发 - 对应线程变量的生命周期:是否被多次赋值?是否在不同作用域中被意外共享?
- 配合
Thread.getState()在调用前打印状态(仅用于诊断,不可用于控制流程)
注意:getState() 返回的是瞬时快照,不能作为线程安全的状态决策依据,仅适合日志排查。










