【问题标题】:Finding the cause for waiting/sleeping threads查找等待/休眠线程的原因
【发布时间】:2011-12-26 13:16:09
【问题描述】:

我注意到我的 java 应用程序(在 tomcat6 上运行)产生了很多不会终止的线程。

所以我创建了一个线程转储并注意到有大量线程在等待,如下所示:

"pool-1-thread-22" prio=5 tid=101b4b000 nid=0x127122000 waiting on condition [127121000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <6c340cee0> (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.LinkedBlockingQueue.take(LinkedBlockingQueue.java:399)
    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:680)
   Locked ownable synchronizers:
    - None

现在的问题是:这些线程在等待什么? 我怀疑类似乎产生了这些线程,但我不知道究竟是什么让这些线程卡住了。

除了逐行撕开类并继续监视线程行为之外,我能做些什么来找出造成这种情况的原因吗?

【问题讨论】:

  • 嗯,他们正在排队等候。具体来说,LinkedBlockingQueue.take() 在队列为空时会无限期阻塞。
  • 这是什么意思?什么队列以及该方法take() 做了什么?
  • 呃,这是你的密码……我们不是通灵者。只是告诉你线程转储告诉你什么。
  • ?我肯定没有写 java.util.*。
  • 你有一个线程。它正在使用阻塞队列。那个队列是空的。您的线程正在阻止尝试从中读取,因为它是空的。除非将某些内容添加到队列中,否则它将永远阻塞在那里。我们看不到您的代码。没有你的代码,没有人能帮助你。

标签: java multithreading


【解决方案1】:

在 tomcat 上,它们通常是请求工作线程等待某人连接。 没什么可担心的。他们已准备好处理同时连接到您服务器的 100 个用户。

【讨论】:

  • 不可能。我可以在我的应用程序中显式单击一个按钮来生成这些线程。单击后,将出现这些线程。一段时间后,这些线程消耗了大量内存,导致服务器崩溃。
  • 如果线程被阻塞(例如,在队列中等待),它们就不能再消耗内存——它们没有运行,因此不能请求任何内存。如果有的话,它们的堆栈很可能会在等待一段时间后被换出,因此实际上会减少实际 RAM 的使用。
  • 我同意@ptyx 的观点。大概单击应用程序中的按钮会向 Tomcat 服务器发送请求。我的猜测是您的配置错误,告诉 Tomcat 能够处理大量请求,因为您想成为企业。 Tomcat 不断在其ThreadPoolExecutor 中创建一个新的Thread,因为它还没有达到corePoolSize。最终导致服务器崩溃,因为您已经为大量线程进行了配置,但不允许有足够的内存来分配这些线程所需的所有堆栈空间。但这只是我的猜测。
  • 是的,我设置了Executors.newFixedThreadPool(3000);,否则当达到这个线程数时应用程序将崩溃。因此,我想找出这些线程不终止的原因,以便减少该数量。
  • 就是这样!我减少了池的大小,现在tomcat似乎可以正确地“回收”池线程,并且不会产生如此多的线程。谢谢,蒂姆!
【解决方案2】:

这些线程是线程池的一部分。更具体地说是 java.util.concurrent.ThreadPoolExecutor。线程正在等待 Runnable/Callable 提交到池中。例如

ExecutorService e = Executors.newFixedThreadPool(10);

将创建 10 个线程等待直到

e.submit(new Runnable(){
  public void run(){ ...}
});

然后将通知一个线程并调用该可运行对象。我不知道它们被用来做什么。您必须找出启动线程池的原因。也许它处理客户端对应用服务器的请求。

【讨论】:

  • 不这么认为。这些线程不是固定的。它们是在用户与应用程序交互时动态创建的。长期使用后有数百个,而不仅仅是 10 个。
  • 我想你必须找出用户交互后会发生什么。正如您在我的示例中看到的那样,任何人都可以创建这些线程。如果您获得更多关于正在发生的事情的代码,我们可以提供帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-04
  • 2013-02-20
  • 2020-04-04
  • 2017-11-28
  • 1970-01-01
相关资源
最近更新 更多