1

我有一个 Java 应用程序,其结构如下:

  • 一个线程监视java.nio.SelectorIO。
  • 线程池处理要立即完成的java.util.concurrent.ScheduledThreadPoolExecutor工作(调度 IO 线程读取的 IO)或延迟后完成的工作,通常是错误。

ScheduledThreadPoolExecutor要创建的线程数有上限;目前应用程序中有 5000 个,但我根本没有调整过这个数字。

运行应用程序一段时间后,我得到了成千上万个具有此堆栈跟踪的线程:

"pool-1-thread-5262" prio=10 tid=0x00007f636c2df800 nid=0x2516 waiting on condition [0x00007f60246a5000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000581c49520> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:196)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2025)
        at java.util.concurrent.DelayQueue.poll(DelayQueue.java:209)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:611)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:602)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
        at java.lang.Thread.run(Thread.java:662)

我认为上述情况是由我对 的调用引起的schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit),这在应用程序中肯定经常发生。这是预期的行为吗?

让所有这些线程挂起似乎根本不会影响应用程序——如果需要一个工作线程,看起来这些TIMED_WAITING线程不会阻止任务在通过该submit方法提交时运行,但我不完全确定那。在这种停放状态下挂起数千个线程会影响应用程序或系统性能吗?

通过该schedule方法提交的任务非常简单:它们基本上只是ChannelSelector. 因此,这些任务的生命周期不是很长,它们只需要在未来的某个时间点执行即可。普通工作线程将执行传统的阻塞 IO 来执行它们的工作,并且通常寿命更长。

一个相关的问题:在显式的单线程中执行延迟任务而不是使用该schedule方法更好吗?也就是说,有一个这样的循环:

DelayedQueue<SomeTaskClass> tasks = ...;
while (true) {
    task<SomeTaskClass> = tasks.take();
    threadpool.submit(task);
}

DelayQueue 是否使用任何工作线程来实现其功能?我今天打算尝试一下,但建议将不胜感激。

4

1 回答 1

1

运行应用程序一段时间后,我得到了成千上万个具有此堆栈跟踪的线程。

除非您实际上计划同时运行 5000 个线程,否则这个数字太高了。如果它们在 IO 上被阻止,那应该没问题。除非您从最小数量的线程开始,否则它们在您的线程转储中的存在意味着在某些时候它们都需要处理提交给执行程序的任务。所以在某个时候,你有 5000 个任务同时运行——阻塞或其他。如果您显示实际的执行程序构造函数调用,我可以更具体。

如果您有时间,使用该上限可能会很好地查看它是否会影响应用程序行为。

在这种停放状态下挂起数千个线程会影响应用程序或系统性能吗?

它们将占用更多内存,这可能会影响 JVM 性能,但否则它不会影响应用程序,除非同时运行太多。他们可能只是在浪费一些系统资源,这是我使用 5000 和其他执行器构造函数参数的唯一原因。

在显式的单线程中执行延迟任务而不是使用 schedule 方法更好吗?

我会说不。几乎任何时候您都可以使用ExecutorService类替换手动线程代码,这是一件好事。我认为完成一项任务然后延迟一段时间的想法是对ScheduledThreadPoolExecutor.

DelayQueue 是否使用任何工作线程来实现其功能?

不,这只是一种BlockingQueue有助于延迟任务的实现。我实际上从未使用过该课程,尽管如果我知道的话我会使用的。使用ScheduledThreadPoolExecutor这个类来完成它的工作,所以使用DelayQueue你自己又是一种浪费。坚持使用 STPE。

于 2012-07-03T18:33:40.653 回答