Thread Lifecycle

Java Thread Status

上图是早期进程的状态,这里所谓“进程状态”指早期的那种“单线程进程”的状态。

对于现在普遍的“多线程进程”,显然,谈论“进程状态”已经没有意义,应该谈论“进程下某个线程的状态”或者直接说“线程状态”。

这里有个误区:其实在 Java 里面,线程是包含6个状态,而不是5个状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* 
* sun.misc.VM
*
* The threadStatus field is set by the VM at state transition
* in the hotspot implementation. Its value is set according to the JVM TI specification GetThreadState function.
*/
private final static int JVMTI_THREAD_STATE_ALIVE = 0x0001;
private final static int JVMTI_THREAD_STATE_TERMINATED = 0x0002;
private final static int JVMTI_THREAD_STATE_RUNNABLE = 0x0004;
private final static int JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER = 0x0400;
private final static int JVMTI_THREAD_STATE_WAITING_INDEFINITELY = 0x0010;
private final static int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020;

/*
* Thread.State
*/
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}

These states are virtual machine states which do not reflect any operating system thread states。

这些状态是虚拟机状态,它不反映任何操作系统的线程状态。

Runnable 与 传统Running 状态的区别

有人常觉得 Java 线程状态中还少了个 Running 状态,这其实是把两个不同层面的状态混淆了。对 Java 线程状态而言,不存在所谓的 Running 状态,它的 Runnable 状态包含了 Running 状态。

为何 JVM 中没有去区分这两种状态呢?现在的时分(time-sharing)多任务(multi-task)操作系统架构通常都是用所谓的“时间分片(time quantum or time slice)”方式进行抢占式(preemptive)轮转调度(round-robin式)。这个时间分片通常是很小的,一个线程一次最多只能在 CPU 上运行比如 10-20ms 的时间(此时处于 Running 状态),也即大概只有 0.01 秒这一量级,时间片用后就要被切换下来放入调度队列的末尾等待再次调度(也即回到 Ready 状态)。

Java中的 RUNNABLE 状态实际上是包含了 Ready 与 Running 的状态的。


从实际来说,线程只有”就绪”、”阻塞”、”运行”三种状态:

  1. 运行状态,线程正在干活的状态;
  2. 就绪状态,CPU正在忙活别的;
  3. 阻塞状态,线程主动让出CPU资源;

NEW 和 TERMINATED 这两种状态其实并不是线程的状态,而是java.lang.Thread对象的状态。可以说,处于 NEW 和 TERMINATED 状态的”线程”其实并不是线程,而只是一个代表着线程对象而已。

所以我们把 NEW 和 TERMINATED 两种状态去掉,那么Java定义的线程状态还有4种:

  1. RUNNABLE
  2. BLOCKED
  3. WAITING
  4. TIMED_WAITING

这四种状态怎么对应到”就绪”、”阻塞”、”运行”这三种状态里呢:

  1. RUNNABLE,对应”就绪”和”运行”两种状态,也就是说处于就绪和运行状态的线程在java.lang.Thread中都表现为”RUNNABLE”;
  2. BLOCKED,对应”阻塞”状态,此线程需要获得某个锁才能继续执行,而这个锁目前被其他线程持有,所以进入了被动的等待状态,直到抢到了那个锁,才会再次进入”就绪”状态;
  3. WAITING,对应”阻塞”状态,代表此线程正处于无限期的主动等待中,直到有人唤醒它,它才会再次进入就绪状态;
  4. TIMED_WAITING,对应”阻塞”状态,代表此线程正处于有限期的主动等待中,要么有人唤醒它,要么等待够了一定时间之后,才会再次进入就绪状态;

Reference