0

我有N個任務,每個任務使用一個固定的線程池的大小,通常會比N.多線程架構n個重複任務

小,因爲通常會有自己特定的延遲時間(N)後重複線程短缺,應優先考慮執行不同的任務,而不是重複最近完成的任務。

我正在考慮使用帶有N個嵌套的ScheduledThreadPoolExecutors的外部ThreadPoolExecutor。我不確定如何以最優方式去解決這個問題,因爲每個類都維護自己的內部線程池。

回答

2

除了通過assylias回答使用PriorityQueue之外,還可以通過簡單執行ThreadPoolExecutor和另一個ScheduledExecutorService在體系結構上解決此問題,該任務將在給定延遲後插入任務。

因此,每個任務都有執行Runnable和插入Runnable,並且在成功執行後,會告訴ScheduledExecutorService在給定延遲後運行插入Runnable,然後將該任務返回到ThreadPoolExecutor。

由於代碼:

// myExecutionTask 
void run() { 
    doSomeWork(); 
    scheduledExecutor.schedule(myInsertionRunnable, 1000, TimeUnit.MILLISECONDS); 
} 

// myInsertionRunnable 
void run() { 
    threadPoolExecutor.execute(myExecutionTask); 
} 

實際上,這將自動循環中的ThreadPoolExecutor的任務,因爲這已經完成了這些任務,將在隊列的末尾。

編輯:正如在評論中討論,用一個非常繁忙的系統上調度的fixedRatefixedDelay功能時,後來添加的任務可能不經常比早先已添加的任務執行,因爲系統似乎更喜歡任務在決定下一個運行時已經在執行。

相反,我上面的解決方案正確地循環這些任務,雖然在繁忙的系統中不能保證所請求的延遲是準確的。所以他們可能會稍後執行,但至少總是按照先進先出順序執行。

+1

這以最簡單的方式實現我想要的。另一個好處是重複的時間間隔只有在完成當前任務後纔開始計數,這正是我想要的。 – Monstieur

+0

我不完全確定,但似乎我可以簡單地使用'ScheduledThreadPoolExecutor.scheduleWithFixedDelay(Runnable命令,long initialDelay,long delay,TimeUnit unit)'來一次性添加所有任務。如果'initialDelay'爲'0',這是否不會自動排列任務,以保證新任務總是在重複之前運行,並且重複將按延遲到期的順序運行? – Monstieur

+0

如果你使用fixedDelay或fixedRate函數,這可能會起作用,但是一旦你在每次執行後都不能改變延遲(如果這甚至是需求的話),第二:如果請求太多的任務運行,它們可能會堆積最終(取決於調度程序的實現,不確定它是如何在內部完成的),因爲新任務可能沒有執行時間。雖然任務也會隨着我的想法一定程度上增加,但所有任務至少保證以半正規方式執行。 – TwoThe

1

你可以使用一個PriorityBlockingQueue並使用時間戳來定義優先級 - 是這樣的:

class Task { 
    AtomicLong lastRun; 
    Runnable r; 

    void run() { 
     r.run(); 
     lastRun.set(System.currentMillis); 
    } 
} 

你ScheduledExecutorService的(一個線程)可接任務Ñ添加到一個PriorityQueue每間隔(N)。

而且你可以在你的FixedThreadPool中運行一個單獨的使用者隊列(使用反向比較器,以便最近運行的任務的優先級較低)。

這是一個粗略,但它應該工作。

+0

在ScheduledThreadPoolExecutor塊中排隊執行任務中的延遲嗎?在線程池大小爲1的情況下,如果我首先添加一個延遲爲10秒的任務,然後添加一個延遲2秒的任務,那麼第二個任務是否會先執行? – Monstieur

+0

@Locutus在我的建議中,由STPE運行的任務是向隊列中添加一個任務,而不是運行它 - 因此它幾乎是瞬間返回。任務由FixedThreadPoolExecutor運行,當線程變爲可用時,將從PriorityQueue接收下一個任務。 – assylias

+0

我問我是在考慮一個變體,而不是你的實現。 – Monstieur