Tomcatアプリケーションサーバーのスレッド数はgrowingです。
分析のためにスレッドダンプを取得したとき。
430スレッドのうち307スレッドがこのステータスであることがわかりました。
サンプルスタックトレース
"pool-283-thread-1" #2308674 prio=5 os_prio=0 tid=0x000000000a916800 nid=0x1101 waiting on condition [0x00002aec87f17000]
Java.lang.Thread.State: WAITING (parking)
at Sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000006d9929ec0> (a Java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at Java.util.concurrent.locks.LockSupport.park(LockSupport.Java:175)
at Java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.Java:2039)
at Java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.Java:442)
at Java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.Java:1067)
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1127)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:617)
at Java.lang.Thread.run(Thread.Java:745)
Locked ownable synchronizers:
- None
"pool-282-thread-1" #2307106 prio=5 os_prio=0 tid=0x000000000a4fb000 nid=0x78e3 waiting on condition [0x00002aec87e16000]
Java.lang.Thread.State: WAITING (parking)
at Sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000006d8ca7bf8> (a Java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at Java.util.concurrent.locks.LockSupport.park(LockSupport.Java:175)
at Java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.Java:2039)
at Java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.Java:442)
at Java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.Java:1067)
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1127)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:617)
at Java.lang.Thread.run(Thread.Java:745)
Locked ownable synchronizers:
- None
環境
JDK: jdk1.8.0_60
OS: Linux
Tomcat: Tomcat-7.0.65
これが問題の原因かどうかは不明です。
これに関するどんな助けにも感謝します。
これは典型的なリソースリークです。アプリケーションのどこかでExecutorService
のようなものを使用していて、作業が完了した後にそのプールを閉じていないため、スレッドが永久に待機しています。
ExecutorService#shutdown()
を呼び出してプールを閉じ、作業が完了した後にそのスレッドを解放/終了する必要があります。
pool-282-thread-1
pool-283-thread-1
のようなスレッド名は、おそらく単一のスレッドプールエグゼキューターを使用していることを示しています(プール番号が大きく、スレッド番号が1しかないため)。 ExecutorService
の背後にある考え方は、アイドル状態のスレッドを再利用して、さらに作業を行うことです。したがって、バックグラウンドで作業する必要があるたびに新しいExecutorService
を作成する必要があるので、単一のインスタンスを共有して、アプリケーションで使用する必要があります。
この問題はアプリケーションで発生しました。毎回ExecutorServiceを作成する代わりに、single ExecutorServiceを使用して修正しました。