ほとんどがアイドル状態の Tomcat サーバーのスレッドダンプを取得すると、多くのスレッドが次のように RUNNABLE 状態で表示される場合があります。
"http-bio-8443-exec-21975" daemon prio=10 tid=0x00007f6f6406c000 nid=0x222a runnable [0x00007f6f156ae000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:516)
at org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:501)
at org.apache.coyote.http11.Http11Processor.setRequestLineReadTimeout(Http11Processor.java:173)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:924)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:309)
- locked <0x00000007cadcd3f8> (a org.apache.tomcat.util.net.SocketWrapper)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
ソースコードの私の解釈は、このスレッドが HTTP キープアライブ接続からの追加データを (タイムアウトで) 待っているということです。そのため、スレッドが RUNNABLE であっても、CPU を消費しません。
Thread.State RUNNABLE javadocは次のように述べています。
実行可能状態のスレッドは Java 仮想マシンで実行されていますが、プロセッサなどのオペレーティング システムからの他のリソースを待機している可能性があります。
したがって、この場合、他のリソースは CPU ではなく I/O になります。
他の質問Java socketRead0 Issueで、ジェフは次のように答えています。
Java ネイティブ メソッドを使用している場合、呼び出しが実際に何らかのイベントを待ってブロックされていても、スタック トレースには RUNNABLE と表示されると思います。本質的に、ネイティブ メソッドが実際に何を行っているかを Java が知る方法はないと思います。そのため、Java はこれらの呼び出しに RUNNABLE のフラグを立てます。私は socketRead0() と socketAccept() でこれを見てきました - どちらも通常ブロックします。
私も同様の結論に達したので、この専用の質問でこの解釈を検証したいと思います。
RUNNABLE Threads を調べて CPU 消費を分析したい場合、ネイティブ メソッドのスレッドのソースコードを詳しく調べて除外する必要があるかもしれません。
要点は、スレッドの状態だけを見るほど簡単ではなく、ソースコードを掘り下げて、特定のネイティブ メソッドが何をしているのかを推測する必要があることです (または、その C または C++ ソースコードを調べることさえあります)。