关于 Java 的线程状态

摘要: 初步谈论了Java中的6种线程状态, 并探讨了它们与操作系统线程状态的异同.

目录

Java 线程有 6 种状态. 在某个给定时间点上, 一个线程只能处于这 6 种状态中的一种.

线程状态的枚举: Thread.State

这 6 种状态被明确地定义在 Thread 类的一个内部枚举类 Thread.State 中:

java 线程状态内部枚举类 Thread.State

它们是:

  • NEW (新建) A thread that has not yet started is in this state.
  • RUNNABLE (可运行) A thread executing in the Java virtual machine is in this state.
  • BLOCKED (阻塞) A thread that is blocked waiting for a monitor lock is in this state.
  • WAITING (等待) A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
  • TIMED_WAITING (计时等待) A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
  • TERMINATED (终止) A thread that has exited is in this state.

注: 以上内容直接来自 State 类中的 Javadoc, 只对状态进行了翻译, 具体的描述后面再分析.

它上面还有个注解 @since 1.5, 暗示了在 JDK1.5 时引入了这些定义.

因此, 说有 6 种线程状态是对 1.5 及以后版本而言.

Thread 类中有一个方法 getState, 返回的就是这里定义的状态.

可用于监控工具分析线程状态, 不作同步工具使用.

线程状态的监控

一些监控工具, 如 VisualVM, 如果进行了完整的 JDK 包安装, 比如在我的机器上, 可以在 C:\Program Files\Java\jdk1.7.0_25\bin 中找到它:

java VisualVM 安装位置

它有个漂亮的小图标, 可以很容易就找到它, 双击就可以打开它了:

java VisualVM 界面

可以看到它自身也是 Java 应用(它还能监控它自身呢), bin 下的 exe 可能仅是个引导的程序. 还有就是我们熟悉的 Eclipse 了.

界面不咋地, 一看就是典型的 Java GUI 的风格...

双击上图中本地列表下的 Eclipse, 则出现如下监控界面, 选择到"线程"的 tab 上:

java VisualVM 监控

上图中勾选了一个叫"Worker-JM"的线程, 可以看到它处于 WAITING 状态下, 具体在下面的 waiting on 上显示了它在一个 ArrayList 对象上等待.

注: 截图中下方的"Thread inspector"窗体是一个插件, 默认是没有安装的.

可在"菜单--工具--插件"下面找到它并安装即可.

虚拟机线程状态 vs 操作系统线程状态

首先要明确一点, 这里所谓的"Java线程状态"指的是虚拟机层面上暴露给我们的状态, 这些状态是由枚举类 Thread.State 明确定义的. 你可能听说过这样的说法, 比如在 Windows 系统下, 很多的虚拟机实现实际都把 Java 线程一一映射到操作系统的**内核线程(kernel thread)**上.

除了 1:1 映射, 还可能有 N:1 或者 N:M 映射.

总之, 世界很乱...

自然, 操作系统的线程也有它自己的状态. 你 Java 有 6 种, Windows 可能有 N 种, 到了 Linux 系统, 它可能有 M 种.

好吧, 我也不知道具体有几种~且不说操作系统各种版本满天飞.

在这里我想说的是, 你管它是 N 种还是 M 种!虚拟机层的存在, 统一了这些差别. 不管它是 N 还是 M 种, 到了 Java 层面它们都被映射到了 6 种状态上来. 自然, 两个层面上有很多状态其实是大同小异的. 至于具体差异, 那是写虚拟机实现的那些家伙们去操心的事.

有可能操作系统中的两种状态在 JVM 中则统一成了一种状态, 也可能操作系统中的一种状态在 JVM 中又细分成了两种状态, 谁知道呢? 你也不想去知道, 反正我是不想去知道.

而很多关于操作系统上的书则常会提到有 5 种**进程(process)**状态:

  • new
  • ready
  • running
  • waiting
  • terminated

os thread state 操作系统 进程(线程)状态

不幸的是, 有很多的书上常常把这些进程状态, 线程状态与 Java 线程状态混在一起谈.

这里所谓进程状态指早期的那种单线程进程的状态.

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

不过有时还是会把"进程状态"和"线程状态"混着去说, 有些系统把线程叫成"轻量级进程"(light-weight process), 所以还是在谈"进程状态".

有时则甚至既不叫"进程", 也不叫"线程", 它们叫"task"或者"job".

总之还是有些乱的, 我们不妨就拿 Windows 系统为例, 用的就是"进程"和"线程"这两种较为标准的叫法, 这时一个进程下至少有一个线程, 线程是 CPU 调度的基本单位, 进程不参与 CPU 调度, CPU 根本不知道进程的存在.

你在"任务管理器"中看到的所谓"进程状态", 跟线程状态不是一回事.

至于 Java 线程的状态, 有的说有 4 种状态, 有的说有 5 种, 各种各样的说法都有.

比如看到 Java 只有 RUNNABLE(可运行的)状态, 就觉得这还不够呀, 应该还有 Running(运行中)状态;

又或者觉得 RUNNABLE 就是 Running, 所以应该还有个 Ready(就绪)状态.

如果我们读下 Thread.State 源码中的注释中, 它说得很清楚:

These states are virtual machine states which do not reflect any operating system thread states. 这些状态是虚拟机状态, 它不反映任何操作系统的线程状态.

它对应的内核线程中的状态可能有 Running 又有 Ready, 在虚拟机层面则可能统一映射成了 RUNNABLE. 如果 Java 中觉得没必要去区分这些, 我们又何必去纠结这些呢?

以 RUNNABLE 为例, 源码中的注释是这样说的: executing in the Java virtual machine(正在Java虚拟机中执行). 至于它是否真正在执行, 不是我们要操心的事.

还有的情况则比如把 Java 状态中的 BLOCKED, WAITING, TIMED_WAITING 三种状态都笼统地称为 blocked 或者 waiting.

操作系统也许只有一种状态, 但这一次, Java 作了细分, 给出了三种状态.

很多声称 Java 线程只有 4 种或 5 种状态常常都是自作主张地合并了这些状态, 把这些东西混为一谈是非常容易引发混乱的. 我们将会在后面具体地谈到.

又或者把 TIMED_WAITING 当作不存在, 从来不提有这个状态.

显然, 这种做法又是受到传统进程状态划分的影响. 尽管它与 WAITING 很像, 我们最好按着 Thread.State 中的定义来, 不要自己随意发挥.

综上所述, 为避免出现混乱, 厘清概念所处的层次是非常重要的. 如无特别说明, 讨论均在 JVM 层面上.

具体而言, 比如当说到 WAITING 状态时, 指的就是 Thread.State.WAITING.

有了以上基础, 才能在接下来更好地去分析这 6 种状态.

具体状态分析

接下来再来细看这 6 个状态, 首先从简单的谈起.

NEW

当使用 new Thread() 创建一个新的线程, 又还没有开始执行(not yet started)它的时候就处于 NEW 状态.

这里所谓"开始执行"具体指调用线程类中的 start 方法.

注意: 你不能直接调用 run 方法, 这样的话还是在原线程上执行. 只有调用 start 方法才会开启新的执行线程, 接着它会去调用 run. 在 start 之后, 线程进入 RUNNABLE 状态, 之后还可能会继续转换成其它状态.

注: 一个线程只能被 start 一次.

TERMINATED

终止状态, 这个也没什么好说的, 完成了执行后(completed execution)或者说退出了(exited). 线程就进入了终止状态.

其它状态

余下的几个状态, 由于无法简单几句说完, 这里先作些简介:

  • RUNNABLE: 前面有提到, 它指"正在 Java 虚拟机中执行".
  • BLOCKED: 等待监视器锁(waiting for a monitor lock ).

    这是一种特殊的 waiting, 实际上就是被 synchronized 方法或者块阻塞.

    monitor 有些书上通常叫"管程", 我也不太确定要怎么叫它. 这里叫成"监视器"也是取字面的意思.

  • WAITING: 无限期等待另一个线程执行一个特别的动作(waiting indefinitely for another thread to perform a particular action ).
  • TIMED_WAITING: 限时等待另一个线程执行一个动作(waiting for another thread to perform an action for up to a specified waiting time ).

详细地介绍留在后面再谈.