簡體   English   中英

ScheduledThreadPoolExecutor.schedule留下的空閑線程

[英]Idle threads left with ScheduledThreadPoolExecutor.schedule

我有一個Java應用程序,其結構如下:

  • 一個線程正在監視IO的java.nio.Selector
  • 一個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方法提交的任務非常簡單:它們基本上只是使用Selector重新安排Channel的時間。 因此,這些任務不是很長壽,它們只需要在將來的某個時刻執行即可。 普通的工作線程將執行傳統的阻塞IO來執行其工作,並且通常壽命更長。

一個相關的問題:在顯式的單線程中執行延遲的任務而不是使用schedule方法是否更好? 也就是說,有一個像這樣的循環:

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

DelayQueue是否使用任何輔助線程來實現其功能? 我今天只打算進行試驗,但是建議將不勝感激。

在運行應用程序一段時間后,我得到了成千上萬個具有此堆棧跟蹤的線程。

除非您實際上計划一次同時運行5000個線程,否則這個數字太高了。 如果它們在IO上受阻,那應該沒問題。 除非您從最小數量的最小線程開始,否則它們在線程轉儲中的存在意味着在某個時候它們都需要處理提交給執行者的任務。 因此,在某個時刻,您一次運行了5000個任務-阻塞或其他。 如果顯示實際的執行程序構造函數調用,我可以更具體一些。

如果有時間,可以嘗試使用該上限來查看它是否確實影響了應用程序的行為。

在此駐留狀態下成千上萬的線程會影響應用程序或系統的性能嗎?

它們將占用更多的內存,這可能會影響JVM性能,但除非一次運行太多,否則它們不會影響應用程序。 他們可能只是在浪費一些系統資源,這就是我要使用5000和其他執行程序構造函數args的唯一原因。

在顯式的單線程中執行延遲的任務而不是使用schedule方法是否更好?

我會說不。 幾乎在任何時候您都可以使用ExecutorService類替換手工線程代碼,這是一件好事。 我認為執行任務然后延遲一段時間的想法是ScheduledThreadPoolExecutor的很好用。

DelayQueue是否使用任何輔助線程來實現其功能?

不會。它只是BlockingQueue實現,有助於延遲任務。 我實際上從未使用過該類,盡管如果知道的話我會用。 ScheduledThreadPoolExecutor使用此類來完成其工作,因此DelayQueue自己使用DelayQueue也是一種浪費。 只需堅持使用STPE。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM