介绍

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过 新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。尤其是当线程启动以后,所有线程都处于等待分配 CPU 时间片,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换。
线程的生命周期 - 图1

新建状态(NEW)

当程序使用new关键字创建一个线程后,该线程处于新建状态,此时的线程情况如下:
JVM 为其分配内存,并初始化成员变量的值;
线程对象没有表现出任何线程的动态特征,程序不会执行线程的执行体。

就绪状态(RUNNABLE)

当线程对象调用了 start() 方法后,该线程就处于就绪状态,此时线程等待系统分配CPU时间片,获取到时间片之后才能执行。

直接调用 run() 方法,这个方法会立即执行,且在 run() 方法返回之前其他线程无法并发执行。 调用了 run() 方法后不能再调用 start() 方法,否则抛出 IllegaIThreadStateExccption 异常。

运行状态(RUNNING)

此时线程获得了CPU时间片,该线程处于运行状态。

阻塞状态(BLOCKED)

处于运行状态的线程在某些情况下,让出自己的CPU时间片,暂停自己的运行,进入阻塞状态。
以下情况会发生阻塞:

  1. 调用 sleep() 方法。
  2. 调用一个阻塞式IO方法,在该方法返回之前,线程会被阻塞。
  3. 试图获得一个同步监视器,但该同步监视器被线程持有。
  4. 调用 suspend() 方法。
  5. 调用 wait() 方法。

    等待状态(WAITING)

    线程处于无限制等待状态,等待一个特殊事件重新唤醒。
    以下操作可以触发唤醒:

  6. 调用 notity()notifyAll() 方法唤醒调用 wait() 方法的线程。

  7. 线程运行结束唤醒 调用 join() 方法的线程。

    wait()和notify()或notifyAll()需要搭配synchronized关键字使用

    从语义角度来讲, 一个线程调用了 wait() 之后, 必然需要由另外一个线程调用 notify() 来唤醒该线程, 所以本质上, wait() 与 notify() 的成对使用, 是一种线程间的通信手段。
    进一步分析, wait() 操作的调用必然是在等待某种条件的成立, 而条件的成立必然是由其他的线程来完成的。 所以实际上, 我们调用 wait() 的时候, 实际上希望达到如下的效果:

    1. // 线程A 的代码
    2. while(!condition){ // 不能使用 if , 因为存在一些特殊情况, 使得线程没有收到 notify 时也能退出等待状态
    3. wait();
    4. }
    5. // do something
    1. // 线程 B 的代码
    2. if(!condition){
    3. // do something ...
    4. condition = true;
    5. notify();
    6. }

    现在考虑, 如果wait() 和 notify() 的操作没有相应的同步机制, 则会发生如下情况:
    第一,【线程A】 进入了 while 循环后(通过了 !condition 判断条件, 但尚未执行 wait 方法), CPU 时间片耗尽, CPU 开始执行线程B的代码。
    第二,【线程B】 执行完毕了 condition = true; notify(); 的操作, 此时【线程A】的 wait() 操作尚未被执行, notify() 操作没有产生任何效果。
    第三,【线程A】执行wait() 操作, 进入等待状态,如果没有额外的 notify() 操作, 该线程将持续在 condition = true 的情形下, 持续处于等待状态得不到执行。
    由此看出, 在使用 wait() 和 notify() 这种会挂起线程的操作时, 我们需要一种同步机制保证, condition 的检查与 wait() 操作, 以及 condition 的更新与 notify() 是互斥的。
    正确的用法如下:

    1. // 线程 A 的代码
    2. synchronized(obj_A)
    3. {
    4. while(!condition){
    5. obj_A.wait();
    6. }
    7. // do something
    8. }
    1. // 线程 B 的代码
    2. synchronized(obj_A)
    3. {
    4. if(!condition){
    5. // do something ...
    6. condition = true;
    7. obj_A.notify();
    8. }
    9. }

    限时等待(TIMED_WAITING)

    比如 ReentrantLock 带有时间限制的加锁。

    死亡状态(DEAD)

    以下方式说明线程处于死亡状态:

  8. run()call() 方法执行完成,正常结束。

  9. 线程抛出一个未捕获的 Exception 或 Error。
  10. 直线调用 stop() 方法,不推荐使用。

    线程执行流程图

    线程的生命周期 - 图2

    参考资料

    Java线程的生命周期