在Java多线程编程中,IllegalThreadStateException属于运行时异常,当线程执行的操作与其当前状态不匹配时就会被抛出,其中线程重复启动是最典型的触发场景。Java的线程从创建到销毁有固定的生命周期,每个阶段只允许执行特定的操作,违反这个规则就会触发异常。

IllegalThreadStateException的定义与触发场景
IllegalThreadStateException继承自RuntimeException,是Java线程操作相关的异常,官方文档中说明该异常会在线程没有处于请求操作所要求的适当状态时抛出。除了线程重复启动之外,还有部分其他场景也可能触发该异常,常见的触发场景如下:
- 对一个已经启动的线程再次调用start()方法
- 尝试让一个已经终止的线程再次进入就绪状态
- 部分线程调度操作中,线程当前状态不支持对应的调度指令
Java线程的核心状态说明
要理解为什么重复启动会触发异常,首先需要明确Java线程的6种核心状态,这些状态定义在Thread.State枚举中:
| 状态名称 | 状态说明 |
|---|---|
| NEW | 线程被创建但还没有调用start()方法,此时线程还没有开始执行 |
| RUNNABLE | 线程正在Java虚拟机中执行,或者正在等待操作系统分配CPU时间片 |
| BLOCKED | 线程因为等待获取监视器锁而被阻塞,比如等待进入synchronized代码块 |
| WAITING | 线程无限期等待另一个线程执行特定操作,比如调用wait()、join()方法 |
| TIMED_WAITING | 线程在指定的等待时间内等待另一个线程执行特定操作,比如调用sleep(long)、wait(long)方法 |
| TERMINATED | 线程执行完毕或者因为异常退出,处于终止状态 |
其中只有处于NEW状态的线程才允许调用start()方法,其他状态的线程调用start()都会直接抛出IllegalThreadStateException。
线程重复启动触发异常的代码示例
下面通过一个简单的代码示例演示重复启动线程如何触发IllegalThreadStateException:
public class ThreadRepeatStartDemo {
public static void main(String[] args) {
// 创建一个线程实例,此时线程处于NEW状态
Thread testThread = new Thread(() -> {
System.out.println("线程正在执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 第一次启动线程,状态从NEW转为RUNNABLE,正常执行
testThread.start();
// 线程执行完成后会进入TERMINATED状态,再次启动就会触发异常
// 即使线程还在执行时再次启动,也会触发异常
try {
// 第二次启动线程,此时线程已经不是NEW状态,会抛出IllegalThreadStateException
testThread.start();
} catch (IllegalThreadStateException e) {
System.out.println("捕获到IllegalThreadStateException:" + e.getMessage());
}
}
}
运行上述代码后,第一次调用start()方法线程正常启动,第二次调用start()时,线程已经处于RUNNABLE或者后续的终止状态,不符合start()方法的调用要求,因此会抛出IllegalThreadStateException,异常信息通常会提示线程已经启动。
start()方法的源码逻辑分析
我们可以查看Thread类中start()方法的源码,理解其内部的校验逻辑:
public synchronized void start() {
// 校验线程状态,如果不是NEW状态,直接抛出IllegalThreadStateException
if (threadStatus != 0)
throw new IllegalThreadStateException();
// 将线程加入线程组
group.add(this);
boolean started = false;
try {
// 调用native方法启动线程
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
源码中的threadStatus是Thread类的成员变量,用来记录线程的状态,当线程处于NEW状态时threadStatus的值为0,一旦调用了start()方法,该值就会被修改为对应的运行状态值,后续再次调用start()时,threadStatus != 0的条件成立,就会直接抛出异常。
如何避免重复启动线程的异常
要避免IllegalThreadStateException,核心是要保证同一个线程实例只调用一次start()方法,常见的规避方案如下:
- 在启动线程前先判断线程的状态,只有处于NEW状态时才调用start()方法,可以通过getState()方法获取线程当前状态
- 如果需要执行多次相同的任务,不要重复启动同一个线程,而是创建新的线程实例来执行任务
- 使用线程池来管理线程,线程池会复用线程资源,不需要手动重复启动线程,也能避免状态异常问题
下面是判断线程状态后再启动的示例代码:
public class SafeThreadStartDemo {
public static void main(String[] args) {
Thread taskThread = new Thread(() -> {
System.out.println("安全启动的线程正在执行");
});
// 判断线程是否为NEW状态,只有是NEW状态才启动
if (taskThread.getState() == Thread.State.NEW) {
taskThread.start();
}
// 后续需要执行相同任务时,创建新的线程实例
Thread newTaskThread = new Thread(() -> {
System.out.println("新的线程实例执行任务");
});
newTaskThread.start();
}
}
其他常见触发场景说明
除了重复启动线程之外,还有一种不常见的场景可能触发IllegalThreadStateException:当线程已经处于终止状态,尝试调用某些需要线程处于活跃状态的方法时,也可能抛出该异常。比如在已经终止的线程上调用join()方法,不过这种情况在实际开发中很少出现,因为线程终止后通常不会再对其进行操作。
总结来说,IllegalThreadStateException的核心触发原因是线程操作与当前状态不匹配,而重复启动线程是最容易出现的错误,开发者只要牢记线程的生命周期规则,避免对同一个线程实例多次调用start()方法,就能有效规避该异常。
IllegalThreadStateExceptionJava线程状态线程重复启动Java异常处理修改时间:2026-06-18 03:54:47