Java Thread 生命周期

547 阅读3分钟

翻译文章 Life Cycle of a Thread in Java

线程的生命周期

java.lang.Thread类包含了一个静态枚举类Thread.State,它定义了线程的潜在状态,且同一时刻线程只能处在以下状态之一:

  1. NEW: 尚未开始执行的新创建的线程
  2. RUNNABLE: 正在运行或准备执行,但正在等待资源分配
  3. BLOCKED: 等待获取监视器锁从而进入 synchronized 代码块或方法
  4. WAITING: 等待其它线程执行特定操作且没有时间限制
  5. TIMED_WAITING: 等待其它线程在指定时间内执行特定操作
  6. TERMINATED: 线程终止 上述所有的状态,都在下图中体现,下面我们会一一讨论这些状态。 image.png

NEW

NEW 表示一个已经被创建,但未启动的线程,线程将会保持这种状态,直到我们调用start()方法。

Runnable runnable = () -> System.out.println("");
Thread t = new Thread(runnable);
logger.info(t.getState().name());

代码会输出以下内容:

NEW

RUNNABLE

当我们创建了一个线程并调用了start()方法,线程状态由 NEW 变成 RUNNABLE, 处于RUNNABLE状态的线程有可能正在运行也可能准备执行,但在等待系统分配资源

在多线程环境下,线程调度器分配时间片段给每个线程,获取时间片段的线程RUNNING一段时间后重回RUNNABLE状态,线程调度器再次分配时间片段给另一个RUNNABLE状态的线程.

Runnable runnable = () -> System.out.println("");
Thread t = new Thread(runnable);
t.start();
logger.info(t.getState().name());

代码会输出以下内容:

RUNNABLE

BLOCKED

线程处于BLOCKED状态时是没有资格运行的。当线程尝试获取synchronized持有的对象的监视器锁失败时会进入BLOCKED状态

尝试模拟下该场景:

public class BlockedState {
    static Logger logger = Logger.getLogger(BlockedState.class.getName());

    public static void main(String[] args) throws InterruptedException {
        Runnable task = () -> loopMethod();

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();

        Thread.sleep(1000);

        logger.info(t1.getState().name());
        logger.info(t2.getState().name());
        System.exit(0);
    }

    public synchronized static void loopMethod() {
        while (true) {
            // 死循环 
            // 导致 t1一直持有BlockedState.class 的锁处于RUNNABLE状态,
            // 而t2因获取不到锁 始终处于BLOCKED状态
        }
    }
}

代码会输出以下内容:

RUNNABLE
BLOCKED

WAITING

依据JavaDocs,当调用以下任意一个方法时,线程会进入WAITING状态:

  1. object.wait()
  2. thread.join()
  3. LockSupport.park() 请注意在wait()和join()方法中,我们没有定义任何时间限制。

现在,我们来模拟一下这个状态:

public class WaitingState {
    static Logger logger = Logger.getLogger(WaitingState.class.getName());

    static Thread t1;

    public static void main(String[] args) {
        Runnable tas2 = () -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info(t1.getState().name());
        };

        Runnable task1 = () -> {
            Thread t2 = new Thread(tas2);
            t2.start();
            try {
                t2.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        t1 = new Thread(task1);
        t1.start();

    }
}

解释下上述代码:

  1. 创建并启动了线程t1
  2. 线程t1中创建并启动了线程t2,
  3. 紧接着调用了 t2.join(), 这会将t1至于WAITING状态,知道t2完成执行
  4. 由于t1正在等待t2完成,所以我们在t2中打印了t1的状态。 此时代码会输出以下内容:
WAITING

TIMED_WAITING

处于TIMED_WAITING状态的线程,会等待另外一个线程在指定时间内执行特定操作

依据JavaDocs,当调用以下任意一个方法时,线程会进入TIMED_WAITING状态:

  1. thread.sleep(long millis)
  2. wait(int timeout) or wait(int timeout, int nanos)
  3. thread.join(long millis)
  4. LockSupport.parkNanos
  5. LockSupport.parkUnti
public class TimedWaitingState {
    static Logger log = Logger.getLogger(TimedWaitingState.class.getName());

    public static void main(String[] args) throws InterruptedException {
        Runnable task = () -> {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        Thread thread = new Thread(task);
        thread.start();

        Thread.sleep(1000);
        log.info(thread.getState().name());
    }
}

5秒后控制台输出如下:

TIMED_WAITING

TERMINATED

这是一个线程的死亡状态。线程完成或异常终止时,线程将处于TERMINATE状态

public class TerminatedState {
    static Logger logger = Logger.getLogger(TerminatedState.class.getName());

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> System.out.println(""));
        t.start();

        // 给线程t足够的时间完成
        Thread.sleep(1000);
        logger.info(t.getState().name());
        // 除了通过状态判断外,还可以通过isAlive()方法判断线程是否存活
        Assert.assertFalse(t.isAlive());
    }
}
TERMINATED