+----------+
| NEW |
+----------+
|
| 1. 调用 start()
v
+----------+ 获取CPU执行权 +----------+
| RUNNABLE | <-------------------- | RUNNING |
| (就绪) | --------------------> | (运行) |
+----------+ CPU时间片用完 +----------+
| |
| 2. 争夺锁失败 | 3. 运行结束 / 异常
v v
+----------+ +----------+
| BLOCKED | |TERMINATED|
+----------+ +----------+
|
| 4. 获取到锁
+---> 返回 RUNNABLE
从图可知,线程的生命周期大体分为5个阶段
NEW
当我们用new创建一个Thread对象的时候,它并不处于执行状态,可以理解成是一个普通的Java对象。
NEW状态通过调用start()方法进入RUNNABLE状态。
RUNNABLE
当线程对象调用start方法进入RUNNABLE状态的时候,此刻才真正地在JVM进程中创建了一个线程。RUNNABLE是一个中间态,称之为可执行状态,就是它具备执行的资格,但需要等待CPU的调度。
Important
但是线程启动不等于就可以立即执行,线程是否运行要取决于CPU的调度。
RUNNING
一旦CPU通过轮询或者其他方式从执行队列中选中了线程,此时它才能真正地执行自己的逻辑代码。
在该状态中,线程的状态可以发生如下的变化:
- 进入TERMINATED状态。调用了stop方法或者判断某个逻辑标识
- 进入BLOCKED状态。1. 调用了sleep方法,或者wait方法加入了waitSet中;2. 进行某个阻塞的IO操作(如网络数据的读写);3. 获取某个锁资源,从而加入到该锁的阻塞队列。
- 进入RUNNABLE状态。1. CPU的调度器轮询使线程放弃执行。2. 线程主动调用yield方法,放弃CPU执行权。
BLOCKED
在该状态中,线程的状态可以发生如下的变化:
- 进入TERMINATED状态。调用了stop方法或者意外死亡(JVM Crash)。
- 进入RUNNABLE状态。1. 线程阻塞的操作结束(如读取了想要的数据字节);2. 线程完成了指定时间的休眠;3. Wait中的线程被其他线程通过notify/notifyall唤醒;4. 线程获取到某个锁资源;5. 线程在阻塞阶段中被打断(如其他线程调用了interrupt方法)
TERMINATED
TERMINATED是一个线程的最终状态,在该状态的线程将不会切换到其他任何状态。一旦线程进入了TERMINATED状态,意味着该线程的整个生命周期都结束了。
有下面这些情况会使线程进入TERMINATED状态:
- 线程运行正常结束,结束生命周期。
- 线程运行出错意外结束。
- JVM Crash,导致所有的线程都结束。