Poison

Thread.State

JVM 中的线程可能处于以下状态:

JVM 中的线程在任意时刻只能处于一种状态。这些状态仅是 JVM 虚拟机中的线程状态,并不反应操作系统的线程状态。

记录这个问题是因为之前在我们的监控服务中经常探测到持续的 RUNNABLE 线程,经过定位,发现是我们自身的用于监控堆转储文件的线程,其实在操作系统中的状态并不是 R,即并不是运行中或位于运行队列中,我们用一个例子来说明,在我们的线程转储中,经常发现如下的线程数据:

1
2
3
4
5
6
"Thread-5" #16 daemon prio=5 os_prio=0 tid=0x00007f4920006800 nid=0x2d runnable [0x00007f49338e9000]
java.lang.Thread.State: RUNNABLE
at sun.nio.fs.LinuxWatchService.poll(Native Method)
at sun.nio.fs.LinuxWatchService.access$600(LinuxWatchService.java:47)
at sun.nio.fs.LinuxWatchService$Poller.run(LinuxWatchService.java:314)
at java.lang.Thread.run(Thread.java:748)

该方法在 JVM 线程转储中一直处于 RUNNABLE 状态,但是,根据 nid=0x2d 我们转换出对应的 Linux 轻量级进程 id:45 通过如下命令查询轻量级进程状态(其中的 1 为 JVM 进程的 id):

1
cat /proc/1/task/45/status | grep 'State:'

可以得到以下输出:

1
State: S (sleeping)

得到的状态为 S,在 Linux 文档中对应的解释为:interruptible sleep (waiting for an event to complete),这也验证了 Java 文档中的说法,JVM 中的线程状态并不反应操作系统中的线程状态。

同理,最常见的 Netty 执行 Epoll 的线程栈帧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"NettyClientWorker-4-7" #424 daemon prio=5 os_prio=0 tid=0x00007f28080ba000 nid=0x1b5 runnable [0x00007f27f2341000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
- locked <0x00000000e11e1d90> (a io.netty.channel.nio.SelectedSelectionKeySet)
- locked <0x00000000e11e1e80> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000e11e1da8> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:756)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:411)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)

其在 JVM 中的线程状态为 RUNNABLE, 在操作系统级别的状态也为 S (sleeping)

Reference

Thread.State (Java Platform SE 8 )
ps(1) - Linux manual page
Processes and Threads (The Java™ Tutorials > Essential Java Classes > Concurrency)