Skip to content

线程六种状态

理解状态,才能读懂线程的一生。

先看一个问题

当你用 jstack 查看线上进程时,看到一堆线程状态:

"pool-1-thread-3" #42 prio=5 os_prio=31 tid=0x00007f8a5400a000 nid=0x5a03 waiting for monitor entry [0x0000700012e3c000]
   java.lang.Thread.State: BLOCKED

"pool-1-thread-2" #40 prio=5 os_prio=31 tid=0x00007f8a54009000 nid=0x5603 waiting on condition [0x0000700012d39000]
   java.lang.Thread.State: TIMED_WAITING

"pool-1-thread-1" #38 prio=5 os_prio=31 tid=0x00007f8a54007000 nid=0x5203 in Object.wait() [0x0000700012c36000]
   java.lang.Thread.State: WAITING

这些 BLOCKEDTIMED_WAITINGWAITING 到底代表什么?线程为什么会进入这些状态?

要回答这些问题,先得搞清楚 Java 线程的六种状态。

六种状态全景图

java
public enum State {
    NEW,          // 新建
    RUNNABLE,     // 可运行(包含就绪和运行中)
    BLOCKED,      // 阻塞(等待锁)
    WAITING,      // 等待(无限期)
    TIMED_WAITING,// 等待(限时)
    TERMINATED    // 终止
}
                    ┌─────────────────────────────────────────┐
                    │               线程生命周期               │
                    └─────────────────────────────────────────┘

    NEW ────────────▶ RUNNABLE ───────────────────────▶ TERMINATED
         start()              run() 正常返回 / 抛异常

    RUNNABLE ──────────────────────────────────────────────────────────┐
         │                                                                  │
         ├──── synchronized 等待锁 ────▶ BLOCKED ◀─── 获取到锁 ───────────┤
         │                                                                  │
         ├──── wait() / join() / park() ──▶ WAITING ◀─── notify / unpark ─┤
         │                                                                  │
         └──── sleep(ms) / wait(ms) / parkNanos() ──▶ TIMED_WAITING ◀─────┘
                                                       超时 / 被唤醒

NEW:新建状态

线程对象创建了,但还没跟操作系统打过招呼:

java
Thread thread = new Thread(() -> {
    System.out.println("hello");
});

System.out.println(thread.getState());  // NEW
// 此时只是一个普通 Java 对象,尚未绑定 OS 线程

特点

  • 只是 new 出来的对象
  • 还没调用 start()
  • 和 OS 线程没有任何关系

RUNNABLE:可运行状态

调用 start() 后进入这个状态。注意,RUNNABLE 内部其实包含了两种情况:

  • 就绪(Ready):在就绪队列里,等 CPU 调度
  • 运行中(Running):正在 CPU 上执行
java
Thread thread = new Thread(() -> {
    // 这个线程在 RUNNABLE 状态
    // 可能是就绪,可能是运行中
    System.out.println("执行中");
});

thread.start();
System.out.println(thread.getState());  // RUNNABLE

重要:Java 无法区分一个 RUNNABLE 线程是「就绪」还是「运行中」。这是 OS 层面的概念。

BLOCKED:阻塞状态

等待获取 synchronized 锁时被阻塞:

java
Object lock = new Object();

Thread thread1 = new Thread(() -> {
    synchronized (lock) {
        // 持有锁 10 秒
        try {
            Thread.sleep(10_000);
        } catch (InterruptedException e) {}
    }
});

Thread thread2 = new Thread(() -> {
    synchronized (lock) {  // 等着拿锁
        System.out.println("拿到锁了");
    }
});

thread1.start();
Thread.sleep(100);  // 确保 thread1 先拿到锁
thread2.start();

System.out.println(thread2.getState());  // BLOCKED

触发条件:等待 synchronized 锁时,自动进入 BLOCKED。

离开条件:锁被释放,自动被唤醒,重新竞争锁。

WAITING:无限期等待

主动调用让出 CPU,等待被唤醒:

java
// 三种方式进入 WAITING:
synchronized (lock) {
    lock.wait();  // 方式1:wait()
}

thread.join();  // 方式2:join() 无参数

LockSupport.park();  // 方式3:park()
java
public class WaitingDemo {

    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();

        Thread waitingThread = new Thread(() -> {
            synchronized (lock) {
                try {
                    lock.wait();  // 无限期等待
                    System.out.println("被唤醒了");
                } catch (InterruptedException e) {}
            }
        });

        waitingThread.start();
        Thread.sleep(100);

        System.out.println(waitingThread.getState());  // WAITING

        // 唤醒它
        synchronized (lock) {
            lock.notify();
        }
    }
}

特点

  • 无限期等待,必须手动唤醒
  • 不占用 CPU
  • 不会自动醒来

TIMED_WAITING:限时等待

带超时的等待,超时自动唤醒:

java
// 五种方式进入 TIMED_WAITING:

Thread.sleep(5000);  // 方式1:sleep

synchronized (lock) {
    lock.wait(5000);  // 方式2:wait() 带超时
}

thread.join(5000);  // 方式3:join() 带超时

LockSupport.parkNanos(5_000_000_000L);  // 方式4:parkNanos

condition.await(5, TimeUnit.SECONDS);  // 方式5:Condition.await()
java
public class TimedWaitingDemo {

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(3000);  // 等 3 秒
                System.out.println("睡醒了");
            } catch (InterruptedException e) {}
        });

        thread.start();
        Thread.sleep(100);

        System.out.println(thread.getState());  // TIMED_WAITING
        thread.join();
    }
}

特点

  • 超时自动唤醒,不用手动通知
  • 和 WAITING 的区别就是有没有超时参数

TERMINATED:终止状态

线程跑完了:

java
Thread thread = new Thread(() -> {
    System.out.println("任务完成");
});

thread.start();
thread.join();

System.out.println(thread.getState());  // TERMINATED

触发条件

  • run() 正常执行完毕
  • run() 抛出未捕获的异常

状态对比

状态等待原因唤醒方式CPU 占用
NEW-start()
RUNNABLE-OS 调度
BLOCKED等锁锁释放
WAITING主动等手动唤醒
TIMED_WAITING超时等超时/唤醒
TERMINATED--

代码演示:完整状态转换

java
public class ThreadStateDemo {

    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        Thread thread = new Thread(() -> {
            System.out.println("1. 状态: " + Thread.currentThread().getState()); // RUNNABLE

            // 进入 TIMED_WAITING
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {}

            // 进入 WAITING
            synchronized (lock) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {}
            }

            System.out.println("4. 状态: " + Thread.currentThread().getState()); // RUNNABLE
        });

        System.out.println("0. 创建线程: " + thread.getState()); // NEW
        thread.start();
        Thread.sleep(50);
        System.out.println("2. 启动后: " + thread.getState()); // TIMED_WAITING

        Thread.sleep(600); // sleep 结束,等锁
        synchronized (lock) {
            System.out.println("3. 等待锁: " + thread.getState()); // WAITING
            lock.notify();
        }

        thread.join();
        System.out.println("5. 结束后: " + thread.getState()); // TERMINATED
    }
}

输出

0. 创建线程: NEW
1. 状态: RUNNABLE
2. 启动后: TIMED_WAITING
3. 等待锁: WAITING
4. 状态: RUNNABLE
5. 结束后: TERMINATED

常见问题

Q1:RUNNABLE 为什么不等于「正在运行」?

因为 OS 的「就绪」和「运行中」对 Java 来说是透明的。Java 只关心线程在不在 OS 的就绪队列里,在就是 RUNNABLE。

Java 视角:
RUNNABLE = 在 CPU 上运行 OR 在就绪队列等待

OS 视角:
Running = 正在 CPU 上执行
Ready = 在就绪队列,等调度

Q2:BLOCKED 和 WAITING 的区别?

BLOCKEDWAITING
触发方式被动(等锁)主动(调用方法)
唤醒方式自动(锁释放)手动(notify)
持有锁是(拿到锁就进不来)否(wait 释放锁)

Q3:sleep() 和 wait() 的区别?

sleep()wait()
所属Thread 静态方法Object 实例方法
释放锁不释放释放
位置要求任何地方必须在 synchronized 内
唤醒方式超时notify / notifyAll

总结

  • 线程有 6 种状态,NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED
  • RUNNABLE 在 Java 中包含「就绪」和「运行中」两种 OS 状态
  • BLOCKED 是等锁被动触发,WAITING 是主动调用方法
  • TIMED_WAITING 是带超时的等待,到时间自动醒
  • 理解状态是分析死锁、性能问题的基础

基于 VitePress 构建