> 文章列表 > Java 线程状态有哪些?

Java 线程状态有哪些?

Java 线程状态有哪些?

文章目录

  • Java 线程状态有哪些?
    • 初始状态(NEW)
    • 可运行状态(RUNNABLE)
      • 就绪状态
      • 运行状态
    • 阻塞状态(BLOCKED)
    • 等待状态(WAITING)
    • 超时等待(TIMED_WAITING)
    • 终止状态(TERMINATED)

Java 线程状态有哪些?

在线程的生命周期中,它需要经历初始状态、可运行状态、阻塞状态、等待状态、超时等待状态和终止状态。线程的状态流转如下图所示。

在这里插入图片描述

下面的示例代码都继承自类,用来按步骤(模拟时间序列)输出线程的状态。

package org.gettingreal.juc.learning.thread;/*** 线程状态打印类*/
public class ThreadStatePrinter {// 记录步骤private static volatile int STEP = 0;// 打印状态public static void printState(Thread thread) {System.out.println("STEP: " + (++STEP) + ", " + thread.getName() + "'s state: " + thread.getState());}}

初始状态(NEW)

继承 Thread 类,或者类实现 Runnable 接口并将其传递给 Thread 类,使用 new 操作符来创建一个线程,线程此时的状态是初始状态。

package org.gettingreal.juc.learning.thread;/*** 线程初始化状态测试*/
public class ThreadNewStateTest extends ThreadStatePrinter {public static void main(String[] args) {Thread t = new Thread();printState(t);// 输出// STEP: 1, Thread-0's state: NEW}}

可运行状态(RUNNABLE)

线程的可运行状态较为复杂,因为隐喻了就绪状态和运行状态。

就绪状态

就绪状态,是指线程有被运行的可能,CPU 分配给该线程时间片,该线程就会进入运行状态。

下面是线程进入就绪状态的场景:

  • 调用线程的 start() 方法
  • 线程 sleep() 方法结束
  • 其他线程 join() 结束
  • 时间片用完或调用线程的 yield() 方法
  • 锁池里面的线程拿到锁后

通过 start() 方法使得线程进入 RUNNABLE 状态。

package org.gettingreal.juc.learning.thread;/*** 线程 RUNNABLE 状态测试*/
public class ThreadRunnableStateWithStartTest extends ThreadStatePrinter {public static void main(String[] args) {Thread t = new Thread();printState(t);t.start();printState(t);// 输出// STEP: 1, Thread-0's state: NEW// STEP: 2, Thread-0's state: RUNNABLE}}

线程 sleep() 方法结束,进入 RUNNABLE 状态。

package org.gettingreal.juc.learning.thread;/*** 线程 RUNNABLE 状态测试*/
public class ThreadRunnableStateWithSleepTest extends ThreadStatePrinter {public static void main(String[] args) throws Exception {Thread t = new Thread(new Runnable() {@Overridepublic void run() {try {// 触发睡眠Thread.sleep(3000);// 睡眠之后打印该线程的状态printState(Thread.currentThread());} catch (InterruptedException e) {e.printStackTrace();}}});printState(t);t.start();printState(t);// 主线程睡眠 1 秒中,为了输出睡眠中线程的状态Thread.sleep(1000);printState(t);// 输出// STEP: 1, Thread-0's state: NEW// STEP: 2, Thread-0's state: RUNNABLE// STEP: 3, Thread-0's state: TIMED_WAITING// STEP: 4, Thread-0's state: RUNNABLE}}

可以看出,当线程调用 sleep() 方法后,线程进入 TIMED_WAITING 状态,等到 sleep 结束,线程又进入到 RUNNABLE 状态。

其他线程 join 结束,线程进入 RUNNABLE 状态。

package org.gettingreal.juc.learning.thread;/*** 线程 RUNNABLE 状态测试*/
public class ThreadRunnableStateWithSleepTest extends ThreadStatePrinter {private static Thread parentThread;private static Thread childThread;public static void main(String[] args) throws Exception {childThread = new Thread(new Runnable() {@Overridepublic void run() {try {// 触发睡眠Thread.sleep(3000);// 睡眠之后打印父线程的状态printState(parentThread);} catch (InterruptedException e) {e.printStackTrace();}}});childThread.setName("childThread");parentThread = new Thread(new Runnable() {@Overridepublic void run() {try {childThread.start();childThread.join();// join 结束后打印父线程状态printState(parentThread);} catch (InterruptedException e) {e.printStackTrace();}}});parentThread.setName("parentThread");printState(parentThread);parentThread.start();printState(parentThread);// 输出// STEP: 1, parentThread's state: NEW// STEP: 2, parentThread's state: RUNNABLE// STEP: 3, parentThread's state: WAITING// STEP: 4, parentThread's state: RUNNABLE}}

可以看出,parentThread 线程在 WAITING 状态之后又恢复到 RUNNABLE 状态。

时间片用完或者调用 yield() 方法。

package org.gettingreal.juc.learning.thread;/*** 线程 RUNNABLE 状态测试*/
public class ThreadRunnableStateWithYieldTest extends ThreadStatePrinter {public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {printState(Thread.currentThread());// 正在运行中的线程,时间片用完或者调用 yield 方法,都会让线程进入 RUNNABLE 抓给你台Thread.yield();printState(Thread.currentThread());}});printState(t);t.start();printState(t);// 输出// STEP: 1, Thread-0's state: NEW// STEP: 2, Thread-0's state: RUNNABLE// STEP: 3, Thread-0's state: RUNNABLE// STEP: 4, Thread-0's state: RUNNABLE}}

运行状态

从就绪状态的线程中选择一个线程,分配给其 CPU 时间片来运行,该线程就进入运行状态。

阻塞状态(BLOCKED)

当线程无法获取锁时,就会进入到阻塞状态。

package org.gettingreal.juc.learning.thread;/*** 线程阻塞状态测试*/
public class ThreadBlockedStateTest extends ThreadStatePrinter {// 使用对象来模拟一把锁private static Object lock = new Object();private static Thread oneThread;private static Thread anotherThread;public static void main(String[] args) throws Exception {oneThread = new Thread(new Runnable() {@Overridepublic void run() {synchronized (lock) {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}});oneThread.setName("oneThread");anotherThread = new Thread(new Runnable() {@Overridepublic void run() {synchronized (lock) {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}});anotherThread.setName("anotherThread");printState(oneThread);printState(anotherThread);oneThread.start();anotherThread.start();printState(oneThread);printState(anotherThread);Thread.sleep(1500);printState(oneThread);printState(anotherThread);Thread.sleep(1500);printState(oneThread);printState(anotherThread);// 输出// STEP: 1, oneThread's state: NEW// STEP: 2, anotherThread's state: NEW// STEP: 3, oneThread's state: TIMED_WAITING// STEP: 4, anotherThread's state: RUNNABLE// STEP: 5, oneThread's state: TIMED_WAITING// STEP: 6, anotherThread's state: BLOCKED// STEP: 7, oneThread's state: TERMINATED// STEP: 8, anotherThread's state: TIMED_WAITING}}

可以看到在第六步时,anotherThread 的状态是 BLOCKED,因为该线程也需要获得 lock 锁才能执行 synchronized 块里面的逻辑。

等待状态(WAITING)

处于等待状态的线程不会被分配 CPU 执行时间,要被显式地唤醒(调用 notify() 方法),否则会处于一直等待的状态。调用 wait() 方法会释放锁,线程会进入等待锁池中。

package org.gettingreal.juc.learning.thread;/*** 线程等待状态测试*/
public class ThreadWaitingStateTest extends ThreadStatePrinter {private static final Object lock = new Object();public static void main(String[] args) throws Exception {Thread t = new Thread(new Runnable() {@Overridepublic void run() {synchronized (lock) {try {// 调用 wait 方法进入等待状态lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}});printState(t);t.start();printState(t);// 睡眠 1 秒钟,让 t 线程的 wait() 方法得到执行Thread.sleep(1000);printState(t);// 通知线程 tsynchronized (lock) {lock.notify();printState(t);}// 输出// STEP: 1, Thread-0's state: NEW// STEP: 2, Thread-0's state: RUNNABLE// STEP: 3, Thread-0's state: WAITING// STEP: 4, Thread-0's state: BLOCKED}}

在线程上调用 wait() 方法,该线程会进入 WAITING 状态,释放 lock 锁。后面的 BLOCKED 状态是因为执行完 notify() 方法之后,线程需要再次获取 lock 锁。

超时等待(TIMED_WAITING)

线程处于超时等待状态的不会被分配 CPU 执行时间,也无需被唤醒,当然也不会释放对应的锁。

package org.gettingreal.juc.learning.thread;/*** 线程超时等待状态测试*/
public class ThreadTimedWaitingStateTest extends ThreadStatePrinter {private static final Object lock = new Object();public static void main(String[] args) throws Exception {Thread t = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}});printState(t);t.start();printState(t);// 睡眠 1 秒钟,让 t 线程的 wait() 方法得到执行Thread.sleep(1000);printState(t);// 输出// STEP: 1, Thread-0's state: NEW// STEP: 2, Thread-0's state: RUNNABLE// STEP: 3, Thread-0's state: TIMED_WAITING}}

终止状态(TERMINATED)

线程的 run() 方法执行完成后,该线程的状态就是终止状态了。

package org.gettingreal.juc.learning.thread;/*** 线程终止状态测试*/
public class ThreadTerminatedStateTest extends ThreadStatePrinter {private static final Object lock = new Object();public static void main(String[] args) throws Exception {Thread t = new Thread(new Runnable() {@Overridepublic void run() {}});printState(t);t.start();printState(t);// 睡眠 1 秒钟,让 t 线程的 wait() 方法得到执行Thread.sleep(1000);printState(t);// 输出// STEP: 1, Thread-0's state: NEW// STEP: 2, Thread-0's state: RUNNABLE// STEP: 3, Thread-0's state: TERMINATED}}