前言

梳理早期与 Thread 状态相关的笔记。

状态分类

通过查看 Thread 源码,我们可以看到在其类内部定义了线程的状态枚举:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Thread implements Runnable {

public enum State {
NEW,

RUNNABLE,

BLOCKED,

WAITING,

TIMED_WAITING,

TERMINATED;
}

...
}

Thread 线程大致分为 6 种,即 NEWRUNNABLEBLOCKEDWAITINGTIMED_WAITINGTERMINATED

其中:

  • NEW: 新建状态(尚未启动的线程状态),即刚 new 出来,还没执行 start() 方法。
  • RUNNABLE:可运行状态,可以细分两种 READY(就绪状态,调用了 start() 方法,等待获取 CPU 资源运行)和 RUNNING(运行状态,已获取到 CPU 资源)。
  • BLOCKED:阻塞状态,等待拿到监视器锁/对象锁进入到同步方法或同步代码块。
  • WAITING:等待状态
  • TIMED_WAITING:超时等待状态
  • TERMINATED:终止状态

状态转换

  • 当线程被new 出来时,处在 NEW 状态
  • NEW 状态的线程调用 start() 方法后会变成 READY 状态。
  • READY 状态的线程拿到 CPU 资源就可以执行任务,此时状态变为 RUNNING
  • RUNNING 状态中的线程会随着遇到不同情况,状态发生不同的变化:

  ① 线程成功执行完方法或中途遇到异常,状态会变为 TERMINATED

  ② 线程在进到同步方法或同步代码块前,如果没有获取到监视器锁/对象锁,那么状态就会变为 BLOCKED

  ③ 线程在运行过程中调用了 Object 的 wait()、Thread 的 join()、LockSupport.park() 方法后,状态会变成 WAITING

  ④ 线程在运行过程中调用了 Object 的 wait(time)、Thread 的 sleep(time)、LockSupport.parkNanos(time)、LockSupport.parkUntil(time) 方法后,状态会变成 TIMED_WAITING

  • 处在 BLOCKED 状态的线程会被放到同步队列中。当持有锁的线程释放锁后会唤醒同步队列的线程,此时同步队列中的线程状态会变为 READY 竞争对象锁,如果竞争成功状态变为 RUNNING。竞争失败则状态再次变回 BLOCKED,被放回同步队列重复操作。
  • 处在 WAITING 状态的线程会被放到等待队列中。当其他线程调用 notify()notifyAll()unpark(thread) 会唤醒等待队列的线程,此时等待队列中的线程状态会变为 READY 去竞争对象锁,如果竞争成功状态变为 RUNNING,从 wait() 方法中返回。竞争失败则状态变成 BLOCKED,被放进同步队列
  • 处在 TIMED_WAITING 状态的线程会被放到等待队列中。有两种情况会唤醒等待队列中的该状态的线程,一种是手动调用 notify()notifyAll()unpark(thread) 方法,另一种是等待时间过后由 JVM 会自动调用 notifyAll() 方法唤醒,然后执行上边描述的操作。

参考资料