在我们的AppServer中,我们看到线程数超过其JMX线程数阈值(Max = 500,Actual = 595)。
我看到没有死锁。我已经进行了一次线程转储,看到595个线程中的大多数,它们大多数属于两类:
1)定时等待中的234个线程(下面显示的线程转储)
"Timer-232" daemon prio=10 tid=0x00007f46c85cd000 nid=0x7b06 in Object.wait() [0x00007f4668001000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000075246c498> (a java.util.TaskQueue)
at java.util.TimerThread.mainLoop(Timer.java:509)
- locked <0x000000075246c498> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:462)
2)处于等待状态的233个线程(如下所示的线程转储)。我想这是阻塞队列的罪魁祸首,特别是延迟队列。
"AsyncHttpClient-Reaper" daemon prio=10 tid=0x00007f469cd4c000 nid=0x7b09 waiting on condition [0x00007f4667cfe000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007524a2908> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
at java.util.concurrent.DelayQueue.take(DelayQueue.java:160)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:609)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:602)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:947)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:662)
你能帮我理解导致线程超过JMX阈值的原因吗?这是我第一次使用线程场景,因此无法进行可靠的分析。提前谢谢。
答案 0 :(得分:2)
看起来你正在用太多的异步请求来捣乱你的系统。限制它们或为这些请求设置最大池数
答案 1 :(得分:2)
一半的线程是java.util.TimerThread
的实例。只要某个东西创建java.util.Timer
的实例,就会创建此线程的实例;每个Timer
实例都会创建自己的线程。
看起来计时器线程处于执行TimerTask
之前等待特定时间段的状态。由于存在许多计时器线程,因此每次要计划Timer
时,代码中可能存在创建新TimerTask
实例的位置。这将最终创建与待处理任务一样多的线程,这可能非常浪费。
如果要运行的任务是短暂且可靠的,则它们都可以共享一个Timer
实例。
但是,如果任务长时间运行,则可能会延迟后续任务的执行。或者,如果任务抛出未捕获的异常,它将取消计时器线程并防止后续任务被执行。如果有可能出现这些问题,则应使用Executors.newScheduledThreadPool
创建单个ScheduledExecutorService
并在其上安排任务,而不是创建新的Timer
实例。