Java 中的线程状态

145 阅读3分钟

Java 语言中关于线程的状态共分为6种,在 Thread 类里面定义了一个枚举类 State 来标识线程状态,分别为 NEW(新建)、RUNNABLE(运行)、BLOCKED(阻塞)、WAITING(等待)、TIMED_WAITING(计时等待)和TERMINATED(终止)。在 Java 代码中,如果可以通过访问 Thread 类的getStat()方法获取当前线程的状态。

NEW:新建状态

NEW 状态表示线程被创建但是未启动,也就是当一个 Thread 对象创建后并且没有调用 start() 方法之前,当前线程状态为 NEW。

public class NewStateExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> System.out.println("当前线程名称:" + Thread.currentThread().getName()));
        System.out.println("当前线程状态:" + thread.getState());
    }
}

RUNNABLE:运行状态

当调用 Thread 对象的 start() 方法后,线程状态由 NEW 转为 RUNNABLE。但是需要注意是,在 Java 中一个处于 RUNNABLE 状态的线程可能在运行,也可能没有运行而处于等待 CPU 分配资源。

public class RunnableStateExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            System.out.println("当前线程名称:" + Thread.currentThread().getName());
        });
        thread.start();
        System.out.println("当前线程状态:" + thread.getState());
    }
}

BLOCKED:阻塞状态

当一个线程进入 synchronized 代码块并且等待获取一个 monitor 锁时或者在调用Object.wait()方法后被唤醒并重新进入 synchronized 代码块后,线程处于 BLOCKED 状态。

示例:代码进入 synchronized 代码块并且等待过去一个 monitor 锁

public class BlockedState1Example {
    public static void main(String[] args) {
        Object obj = new Object();

        Thread thread = new Thread(() -> {
            synchronized (obj) {
                System.out.println("获取到锁,线程运行");
            }
        });

        synchronized (obj) {
            thread.start();
            System.out.println("线程状态:" + thread.getState());

            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

示例:线程调用 Object.wait() 方法后被唤起重新进入 synchroized 代码块

public class BlockedState2Example {
    public static void main(String[] args) {
        Object obj = new Object();
        Thread thread1 = new Thread(() -> {
            synchronized (obj) {
                try {
                    System.out.println("子线程1运行成功,进入等待状态");
                    obj.wait();
                    System.out.println("子线程1的状态:" + Thread.currentThread().getState());
                    System.out.println("子线程1重新运行");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (obj) {
                try {
                    // 模拟一些工作
                    System.out.println("子线程1的状态:" + thread1.getState());
                    System.out.println("子线程2执行一些工作");
                    Thread.sleep(2000);
                    System.out.println("子线程2工作结束,唤起其他线程");
                    obj.notifyAll();
                    System.out.println("子线程1的状态:" + thread1.getState());
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

WAITING:等待状态

当一个线程执行了Object.wait()(不设置等待时间)、Thread.join()(不设置等待时间)或者LockSupport.park后,该线程的状态从 RUNNABLE 切换到 WAITING 状态,等待其他线程执行特定的操作。例如,一个线程 A 执行了某个对象的 wait() 方法,那么需要等待其他线程执行该对象的 notify() 或者 notifyAll() 方法后,线程 A 才能继续运行。又或者,一个线程 B 执行了 join() 方法,那么只能等待那个线程执行完,线程 B 才能继续执行。

示例:线程调用 join 方法等待其他线程执行完成

public class WaitingStateExample {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            try {
                Thread.sleep(3000);
                System.out.println("线程1执行完毕");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                thread1.join();
                System.out.println("线程2执行完毕");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        thread2.start();
        thread1.start();

        System.out.println("线程2的状态:" + thread2.getState());
        Thread.sleep(1000);
        System.out.println("线程2的状态:" + thread2.getState());
    }
}

TIMED_WAITING:计时等待状态

当一个线程执行了Object.wait()(设置超时时间)、Thread.join()(设置超时时间)、Thread.sleep()(设置超时时间)或者LockSupport.parkNanos/LockSupport.parkUntil后,该线程的状态从 RUNNABLE 切换到 TIMED_WAITING 状态。

TERMINATED:终止状态

当线程执行完成或者出现未处理的异常,线程的状态即为 TERMINATED 状态。

总结

状态切换

LockSupport.park/unpark 与 Object.wait/notify 的对比

特性LockSupport.park/upparkObject.wait/notify
是否需要锁不需要必须在 synchronized 代码块中
顺序问题顺序无关,unpark 可以在 park 前面,效果会被记录下来,后续启动 park 不会阻塞线程必须 先 wait 然后 notify
适用场景更灵活、低级别控制较高层次的同步控制
虚假唤醒处理可结合标记处理必须结合条件变量处理

Thread.sleep 和 Object.wait 的对比

特性Object.wait()Thread.sleep()
释放锁
在哪调用synchronized 代码块代码任意地方
唤醒方式notify() 或者 notifyAll()超时或中断
用途线程间通信线程暂停执行