
1.7 线程的运行状态
线程从启动到最终销毁,整个生命周期会经历不同的状态,在Java中,线程一共有6种状态。
• NEW,新建状态,也就是调用new Thread()时的状态。
• RUNNABLE,运行状态,通过start()方法启动线程后的状态。
• BLOCKED,阻塞状态,当线程执行synchronized代码,并且未抢占到同步锁时,会变成该状态。
• WAITING,调用Object.wait()等方法,会让线程变成该状态。
• TIMED_WAITING,超时等待状态,如sleep(timeout),超时后会自动唤醒。
• TERMINATED,终止状态,线程的run()方法中的指令执行完成后的状态。
1.7.1 线程运行状态演示
在本节中主要演示线程状态的转化。
TIMED_WAITING状态

上述代码运行后,使用jstack工具查看线程的dump信息,会看到如下内容,可以很明显地看到,通过sleep()方法阻塞的线程进入了TIMED_WAITING状态。

WAITING状态

WAITING状态采用Object.wait()方法来实现,上述代码运行后,使用jstack工具查看到线程的dump日志,得到如下结果。

BLOCKED状态


BLOCKED状态只有在synchronized锁阻塞时存在。上述代码创建了两个线程BLOCKED_T1和BLOCKED_T2来执行如下任务。

了解这些状态有助于排查因CPU占用率较高导致的一些问题,后面会举案例来说明。
jstack工具使用方法如下。
• 打开终端命令,输入“jps”(显示当前所有Java进程pid)。
• 根据获取的pid可以打印指定Java进程ID的线程dump的信息。
1.7.2 线程运行状态流转图
图1-6表示Java线程的运行状态及触发状态变更的方法,该图对RUNNABLE状态进行了拆分描述,增加了CPU调度之前和调度之后的场景,实际上还是只有一种RUNNABLE状态。

图1-6 Java线程的运行状态及触发状态变更的方法