我有一个 Java 应用程序,其结构如下:
- 一个线程监视
java.nio.Selector
IO。 - 线程池处理要立即完成的
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
方法提交的任务非常简单:它们基本上只是Channel
用Selector
. 因此,这些任务的生命周期不是很长,它们只需要在未来的某个时间点执行即可。普通工作线程将执行传统的阻塞 IO 来执行它们的工作,并且通常寿命更长。
一个相关的问题:在显式的单线程中执行延迟任务而不是使用该schedule
方法更好吗?也就是说,有一个这样的循环:
DelayedQueue<SomeTaskClass> tasks = ...;
while (true) {
task<SomeTaskClass> = tasks.take();
threadpool.submit(task);
}
DelayQueue 是否使用任何工作线程来实现其功能?我今天打算尝试一下,但建议将不胜感激。