目录
前言:
1. Java线程一共有几种状态
Java 在 java.lang.Thread.State 枚举类中明确定义了6种线程状态,和操作系统五层线程模型做了区分,把阻塞细分为三类,方便开发调试。
| 状态枚举常量 | 状态名称 | 核心含义 | 进入该状态的常用API |
|---|---|---|---|
| NEW | 新建状态 | 仅创建Thread对象,未调用start(),无操作系统内核线程 | new Thread() |
| RUNNABLE | 可运行状态 | 包含操作系统就绪、运行两种状态,等待CPU或正在执行run() | start()、唤醒/超时后 |
| BLOCKED | 同步阻塞状态 | 争抢synchronized同步监视器锁失败,等待释放锁 | 进入同步代码块锁被占用 |
| WAITING | 无限等待状态 | 无超时永久等待,主动释放锁,需其他线程手动唤醒 | Object.wait()、Thread.join()、LockSupport.park() |
| TIMED_WAITING | 限时等待状态 | 带超时时间等待,时间到自动唤醒,无需外部通知 | Thread.sleep(long)、Object.wait(long)、join(long) |
| TERMINATED | 终止状态 | 线程生命周期结束,run执行完毕或抛出未捕获异常 | run()执行完成、运行时抛出未捕获异常 |
当然我们可以也可以这么简单的认为:
- NEW: 老板安排了工作,但是还没有行动
- RUNNABLE: 正在工作或者即将进行工作
- TERMINATED: 工作完成状态
- 其他状态我们都能认为它正在等着别人完成工作,轮到自己接手
1.1 NEW 新建状态
- 产生时机:仅执行
new Thread()创建线程对象,未调用 start(); - 核心特征:只存在Java堆中的对象,操作系统没有创建对应的内核线程,无法参与CPU调度;
举一个简单的例子:
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("我是MyThread");
});
System.out.println(thread.getState());
}
我们创建了线程,但是我们还没有进行调用start方法
我们调用getState方法能查看当前线程状态;

1.2 RUNNABLE 可运行状态
JVM把操作系统「就绪态、运行态」合并为 RUNNABLE:
- 就绪:等待CPU分配时间片;
- 运行:正在执行 run() 方法业务代码;
- 进入该状态场景:调用start()、锁竞争成功、等待超时/被唤醒后。
举个例子:run方法中循环打印0~9
public static void main(String[] args) {
Thread thread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.print(i+" ");
}
});
System.out.println("调用前:"+thread.getState());
thread.start();
System.out.println("调用后:"+thread.getState());
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
当我们调用start方法并创建出线程后调用getState 前后的结果:

1.3 BLOCKED 同步阻塞状态
仅和synchronized内置同步锁绑定:
此时我们就得了解什么是锁?
当多个线程同时操作同一个共享变量 / 共享代码,会出现数据错乱;
锁:同一时间只允许一个线程拿到锁进入同步代码执行,其他没拿到锁的线程排队等待,以此保证数据安全。
- 触发条件:线程尝试进入同步代码块/同步方法,但监视器锁被其他线程持有;
- 释放条件:持有锁的线程执行完同步代码,当前线程竞争到锁,回到RUNNABLE;
- 注意:锁阻塞不会进入BLOCKED,只会进入WAITING。
此时我们可以创建一个死锁来观察线程状态:
举个例子:车钥匙在家里面,而家钥匙在车里面(此时两把锁只有一把,不请开锁师傅的情况下此时就构成了死锁)
public static void main(String[] args) {
Object lock1 = new Object();
Object lock2 = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("t1拿到t1钥匙");
synchronized (lock2) {
System.out.println("t1拿到t2钥匙");
}
}
});
Thread t2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("t2拿到t2钥匙");
synchronized (lock1) {
System.out.println("t2拿到t1钥匙");
}
}
});
t1.start();
t2.start();
}
此时我们可以打开JavaJDK包中的jconsole.exe

此时线程的状态就是:BLOCKED
1.4 WAITING 死等待状态
当我们代码出现死循环或者sleep这样的情况下,并且别的线程处于等待的情况之下,就会出现这样的情况;
- 进入API:
Object.wait()、Thread.join()、LockSupport.park(); - 唤醒条件:其他线程执行`notify()/notifyAll()`、目标join线程执行结束、`unpark()`;
- 等待期间不占用CPU资源。
例如:我们创建一个线程,并且线程中休眠100秒
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
thread.join();
}
此时通过结果我们能看见主线程的状态就是WAITING

1.5 TIMED_WAITING 限时等待状态
带固定超时时间的等待,时间耗尽自动唤醒,无需其他线程通知:
- 进入API:
Thread.sleep(long)、Object.wait(long)、Thread.join(long)、LockSupport.parkNanos(); - 两种唤醒方式:①等待时间自动到期;②其他线程提前调用notify/unpark唤醒
例如:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
thread.join(50000);
}
当代码运行时会创建线程,线程名字默认为:Tread-数字的形式;

1.6 TERMINATED 终止状态
线程生命周期彻底结束,状态不可逆,无法重新启动:
- 两种终止场景:线程中run()方法正常执行完毕、线程运行并没有抛出未捕获的异常;
- 限制:已经终止的线程再次调用
start(),直接抛出IllegalThreadStateException异常。
例如:run方法中输出hello world;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("hello world");
});
thread.start();
thread.join();
System.out.println(thread.getState());
}
此时方法run里面逻辑彻底结束,我们通过的打印可以看见TERMINATED

2. 线程状态之间的切换条件
2.1 NEW → RUNNABLE 转换
唯一转换方式:调用线程对象的 thread.start();
注意:一个线程仅能调用一次start(),重复调用直接抛出异常。
正如:我们上述之前将过的这个例子,这里就不在具体讲解;
public static void main(String[] args) {
Thread thread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.print(i+" ");
}
});
System.out.println("调用前:"+thread.getState());
thread.start();
System.out.println("调用后:"+thread.getState());
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
2.2 RUNNABLE / BLOCKED 互相转换
- RUNNABLE → BLOCKED:线程执行synchronized代码块,同步锁被其他线程占用;
- BLOCKED → RUNNABLE:持有锁的线程退出同步代码块释放锁,当前线程竞争获取锁。
例如:线程1:先持有锁,持有2秒再释放,
线程2:启动就抢锁,抢不到进入BLOCKED
public static void main(String[] args) throws InterruptedException {
Thread threadA = new Thread(() -> {
synchronized (lock) {
System.out.println("线程A 抢到锁,当前状态:RUNNABLE");
try {
// 持有锁2秒,让线程B去竞争锁、进入BLOCKED
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程A 执行完毕,释放锁");
}
}, "线程A");
Thread threadB = new Thread(() -> {
System.out.println("线程B 尝试竞争锁");
synchronized (lock) {
System.out.println("线程B 成功抢到锁,从BLOCKED变回RUNNABLE");
}
}, "线程B");
threadA.start();
Thread.sleep(300);
threadB.start();
}
threadB执行synchronized(lock)抢锁,锁被 A 占用
RUNNABLE → BLOCKEDthreadA同步代码块执行结束,自动释放锁- JVM 调度阻塞队列里的 threadB 重新竞争锁,获取锁成功
BLOCKED → RUNNABLE

2.3 RUNNABLE / WAITING / TIMED_WAITING 互相转换
- RUNNABLE → WAITING:同步块内调用wait()、执行无参join()、LockSupport.park();
- RUNNABLE → TIMED_WAITING:sleep(long)、wait(long)、join(long);
- WAITING / TIMED_WAITING → RUNNABLE:被notify唤醒、等待超时、线程interrupt中断。
示例 1:RUNNABLE ↔ WAITING(wait () 无时限等待)
public static void main(String[] args) throws InterruptedException {
Thread waitThread = new Thread(() -> {
synchronized (lock) {
System.out.println("等待线程:持有锁,当前状态 RUNNABLE");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("等待线程:被唤醒,回到RUNNABLE继续执行");
}
},"t1");
waitThread.start();
// 主线程休眠1秒,保证子线程先执行wait()进入等待
Thread.sleep(30000);
Thread notifyThread = new Thread(() -> {
synchronized (lock) {
System.out.println("唤醒线程:执行notify()");
lock.notify();
}
}, "t2");
notifyThread.start();
}

示例 2:RUNNABLE ↔ TIMED_WAITING(sleep () 限时等待)
public static void main(String[] args) {
Thread sleepThread = new Thread(() -> {
System.out.println("限时线程:启动,状态 RUNNABLE");
try {
// 2. RUNNABLE → TIMED\_WAITING,限时等待3秒
Thread.sleep(3000);
} catch (InterruptedException e) {
System.out.println("限时线程:被中断,提前回到RUNNABLE");
return;
}
// 等待时间耗尽自动恢复:TIMED\_WAITING → RUNNABLE
System.out.println("限时线程:3秒等待结束,回到RUNNABLE");
});
sleepThread.start();
}

2.4 任意状态转为 TERMINATED
无论线程处于RUNNABLE、BLOCKED、WAITING、TIMED_WAITING,满足下面任意一条都会进入终止状态:
- run()方法全部代码正常执行完成;
- 线程运行过程抛出未捕获的异常,中断执行流程。

366

被折叠的 条评论
为什么被折叠?



