Java 多线程基础-03:线程状态和中断

3 阅读5分钟

前言

本文主要介绍Java线程的六种线程状态、线程状态之间的流转和Java中的线程中断机制。

Java线程不是简单的代码执行单元,而是有着完整生命周期的复杂对象。它从诞生(NEW)到死亡(TERMINATED),其间经历了RUNNABLE的活跃、BLOCKED的等待、WAITING的休眠等多种状态。每个状态的转换都遵循着严格的规则,理解这些规则不仅有助于我们编写正确的并发代码,更能让我们在调试时准确定位问题所在。

而Java提供的中断机制是一种精巧的协作式控制手段——它不是粗暴的“杀戮命令”,而是一种优雅的“请求信号”。线程可以选择响应这个信号,清理资源后从容退出;也可以选择忽略它,继续自己的使命。这种设计哲学体现了Java在并发控制上的深思熟虑:将控制的主动权交给线程自身。

1. Java线程状态

Java 线程有 6 种状态,定义在 java.lang.Thread.State 枚举中:

public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

状态总览表:

状态枚举值触发条件备注
NEW
新建
Thread.State.NEWnew Thread() 后,start()线程对象已创建,但尚未启动
RUNNABLE
可运行
Thread.State.RUNNABLE调用 start() 方法后包含操作系统中的"就绪"和"运行"两种状态
BLOCKED
阻塞
Thread.State.BLOCKED等待进入 synchronized 代码块/方法仅针对 synchronized,Lock接口不会进入此状态
WAITING
无限等待
Thread.State.WAITING调用以下方法:
Object.wait()
Thread.join()
LockSupport.park()
无超时时间的等待
TIMED_WAITING
超时等待
Thread.State.TIMED_WAITING调用以下方法:
Thread.sleep(ms)
Object.wait(timeout)
Thread.join(timeout)
LockSupport.parkNanos()
LockSupport.parkUntil()
有超时时间的等待
TERMINATED
终止
Thread.State.TERMINATEDrun() 方法执行结束或异常退出线程生命周期结束

代码示例:状态查看

public class ThreadStateDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            try {
                System.out.println("线程启动后状态: " + Thread.currentThread().getState()); // RUNNABLE
                Thread.sleep(1000); // 进入 TIMED_WAITING
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        System.out.println("创建后状态: " + t.getState()); // NEW
        
        t.start();
        Thread.sleep(100); // 让线程启动
        
        System.out.println("启动后状态: " + t.getState()); // TIMED_WAITING (sleeping)
        
        t.join();
        System.out.println("结束后状态: " + t.getState()); // TERMINATED
    }
}

2. 线程状态流转

graph TD
    A[NEW<br>新建] -->|调用 start| B[RUNNABLE<br>可运行]
    B -->|获取CPU时间片| C[RUNNING<br>实际运行中]
    C -->|时间片用完| B
    B -->|等待IO/资源| D[WAITING/TIMED_WAITING<br>等待/超时等待]
    D -->|被通知/超时| B
    B -->|等待synchronized锁| E[BLOCKED<br>阻塞]
    E -->|获取锁| B
    B -->|run方法结束| F[TERMINATED<br>终止]
    
    C -.->|Java状态机制中<br>RUNNABLE已包含运行状态| B

状态转换触发条件表

转换方向触发条件方法调用示例
NEW → RUNNABLE启动线程thread.start()
RUNNABLE → BLOCKED竞争 synchronized 锁失败synchronized(obj) { ... }
BLOCKED → RUNNABLE获取到 synchronized 锁锁被释放后竞争成功
RUNNABLE → WAITING无限期等待obj.wait()thread.join()
WAITING → RUNNABLE被通知/中断obj.notify()thread.interrupt()
RUNNABLE → TIMED_WAITING有限期等待Thread.sleep(1000)obj.wait(1000)
TIMED_WAITING → RUNNABLE超时/被通知/中断超时结束、obj.notify()thread.interrupt()
RUNNABLE → TERMINATED线程执行完毕run() 方法正常结束或抛出未捕获异常

3. Java线程中断

Java 中断核心: 简单来说,中断就是临时打断线程的工作。在Java线程里面, 中断是协作式的,不是强制终止。Java线程受到中断只是设置一个中断标志位,不会立即停止线程,线程自己决定如何响应中断。

中断相关的核心三个方法如下:

// 1. 中断线程(设置中断标志)
public void interrupt() {
    // 如果线程在 WAITING/TIMED_WAITING 状态,会抛出 InterruptedException
    // 并清除中断标志
}

// 2. 检查中断标志(不清除)
public boolean isInterrupted() {
    return interruptFlag;  // 只是检查,不修改
}

// 3. 检查并清除中断标志(静态方法)
public static boolean interrupted() {
    boolean flag = currentThread().interruptFlag;
    if (flag) {
        currentThread().interruptFlag = false;  // 清除标志
    }
    return flag;
}

中断对不同状态的影响:

线程状态interrupt() 效果中断标志位
NEW无效果保持 false
RUNNABLE仅设置标志位true
BLOCKED仅设置标志位true
WAITING抛出 InterruptedException清除为 false
TIMED_WAITING抛出 InterruptedException清除为 false

代码示例:


public class DifferentStateInterruptDemo {
    public static void main(String[] args) {
        // 专门用于 WAITING 示例的锁对象,避免与 BLOCKED 示例竞争同一把锁
        final Object waitLock = new Object();

        // 1. RUNNABLE 状态的中断
        Thread runnableThread = new Thread(() -> {
            long sum = 0;
            while (!Thread.currentThread().isInterrupted()) {
                sum++; // 纯CPU计算,不会自动检查中断
            }
            System.out.println("计算线程收到中断,sum=" + sum);
        });

        // 2. WAITING 状态的中断
        Thread waitingThread = new Thread(() -> {
            synchronized (waitLock) {
                try {
                    waitLock.wait(); // WAITING 状态
                } catch (InterruptedException e) {
                    System.out.println("等待线程被中断");
                }
            }
        });

        // 3. TIMED_WAITING 状态的中断
        Thread sleepingThread = new Thread(() -> {
            try {
                Thread.sleep(10000); // TIMED_WAITING状态
            } catch (InterruptedException e) {
                System.out.println("睡眠线程被中断");
            }
        });

        // 4. BLOCKED 状态的中断
        Thread blockedThread = new Thread(() -> {
            System.out.println("blockedThread: 准备获取类锁...");
            synchronized (DifferentStateInterruptDemo.class) {
                System.out.println("blockedThread: 获取到类锁,isInterrupted="
                        + Thread.currentThread().isInterrupted());
            }
            System.out.println("blockedThread: 运行结束");
        });

        // 启动线程
        runnableThread.start();
        waitingThread.start();
        sleepingThread.start();

        // 先让主线程持有类锁,再启动 blockedThread,使其进入 BLOCKED 状态
        synchronized (DifferentStateInterruptDemo.class) {
            blockedThread.start();
            try {
                // 短暂休眠,确保 blockedThread 已经因为竞争锁进入 BLOCKED 状态
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // 恢复中断标记,交给后续逻辑决定是否继续
                Thread.currentThread().interrupt();
            }
            System.out.println("blockedThread 当前状态: " + blockedThread.getState());

            // 在 BLOCKED 状态下对其调用 interrupt()
            blockedThread.interrupt();
            try {
                // 短暂休眠,确保 blockedThread 已经受到interrupt影响
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // 恢复中断标记,交给后续逻辑决定是否继续
                Thread.currentThread().interrupt();
            }
            System.out.println("主线程在 BLOCKED 状态下中断 blockedThread");
        }

        // 中断所有线程
        runnableThread.interrupt();
        waitingThread.interrupt();
        sleepingThread.interrupt();
        // 对 blockedThread 而言,刚才的 interrupt() 只是在其仍然 BLOCKED 时设置了中断标记,
        // 等它真正拿到锁并继续执行时,通过 isInterrupted() 可以观察到这一点。

        try {
            blockedThread.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        System.out.println("blockedThread 最终状态: " + blockedThread.getState());
    }
}

运行结果:

blockedThread: 准备获取类锁...
blockedThread 当前状态: BLOCKED
主线程在 BLOCKED 状态下中断 blockedThread
睡眠线程被中断
等待线程被中断
计算线程收到中断,sum=385188478
blockedThread: 获取到类锁,isInterrupted=true
blockedThread: 运行结束
blockedThread 最终状态: TERMINATED