运行的线程太多

时间:2014-08-29 14:38:31

标签: java multithreading

在我们的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阈值的原因吗?这是我第一次使用线程场景,因此无法进行可靠的分析。提前谢谢。

2 个答案:

答案 0 :(得分:2)

看起来你正在用太多的异步请求来捣乱你的系统。限制它们或为这些请求设置最大池数

答案 1 :(得分:2)

一半的线程是java.util.TimerThread的实例。只要某个东西创建java.util.Timer的实例,就会创建此线程的实例;每个Timer实例都会创建自己的线程。

看起来计时器线程处于执行TimerTask之前等待特定时间段的状态。由于存在许多计时器线程,因此每次要计划Timer时,代码中可能存在创建新TimerTask实例的位置。这将最终创建与待处理任务一样多的线程,这可能非常浪费。

如果要运行的任务是短暂且可靠的,则它们都可以共享一个Timer实例。

但是,如果任务长时间运行,则可能会延迟后续任务的执行。或者,如果任务抛出未捕获的异常,它将取消计时器线程并防止后续任务被执行。如果有可能出现这些问题,则应使用Executors.newScheduledThreadPool创建单个ScheduledExecutorService并在其上安排任务,而不是创建新的Timer实例。