2009-10-05 126 views
12

假設我有一個任務是從java.util.concurrent.BlockingQueue中提取元素並處理它們。ScheduledExecutorService具有可變延遲

public void scheduleTask(int delay, TimeUnit timeUnit) 
{ 
    scheduledExecutorService.scheduleWithFixedDelay(new Task(queue), 0, delay, timeUnit); 
} 

如果可以動態更改頻率,我該如何安排/重新安排任務?

  • 的想法是把數據更新流和批量它們傳播到GUI
  • 用戶應該能夠改變更新頻率
+0

我不清楚你爲什麼使用阻塞隊列。 如果你的隊列是空的。我假設你的計劃任務將被阻止。你的意圖是?這可能會混淆任務調度程序的時間。 – 2009-10-05 10:07:18

+0

我選擇了ArrayBlockingQueue實現,因爲它必須是線程安全的,尊重FIFO排序並且有界。即使任務阻塞,它應該不會混淆任務調度嗎? – parkr 2009-10-05 10:15:00

+0

你在使用BlockingQueue實現方面是正確的(事實上ScheduledThreadPoolExecutor在內部使用了一個)。但是,爲什麼使用計時器將更新傳播到GUI?爲什麼不實時做?是否有更新?你關心Swing線程旋轉嗎? – Adamski 2009-10-05 10:43:29

回答

6

我不認爲你可以改變固定利率延遲。我認爲您需要使用schedule()執行一次性操作,並在完成後再次安排(如果需要,修改超時時間)。

+1

謝謝 - 我做了'延遲'實例變量並添加了一個私有方法來執行以下操作:while(!executorService.isShutdown){executorService.schedule(new Task(queue),delay,TimeUnit.MILLISECONDS); } – parkr 2009-10-06 01:52:24

1

你不是應該使用scheduleAtFixedRate如果您嘗試使用特定間隔處理多個隊列任務? scheduleWithFixedDelay只會等待指定的延遲,然後從隊列中執行一個任務。

無論哪種情況,ScheduledExecutorService中的schedule*方法都將返回ScheduledFuture引用。如果您想更改費率,則可以取消ScheduledFuture並以不同的費率重新安排任務。

+0

scheduleWithFixedDelay(...) - 創建並執行一個定期動作,該動作在給定的初始延遲後首先變爲有效,隨後在一次執行終止和下一次執行終止之間給定延遲。如果任務的任何執行遇到異常,則後續執行被禁止。否則,任務將僅通過取消或終止執行者而終止。 – parkr 2009-10-05 10:17:17

+0

你可以舉一個取消和重新計劃的代碼示例嗎?有什麼更新正在進行? – parkr 2009-10-05 10:19:14

0

scheduleWithFixedDelay(...)返回RunnableScheduledFuture。爲了重新安排時間,您可以取消並重新安排時間。要重新安排它,你可能只是包裹RunnableScheduledFuture機智一個新的Runnable:

new Runnable() { 
    public void run() { 
     ((RunnableScheduledFuture)future).run(); 
    } 
}; 
22

使用schedule(Callable<V>, long, TimeUnit)而非scheduleAtFixedRatescheduleWithFixedDelay。然後確保您的Callable 在未來某個時間重新安排自己或新的Callable實例。例如:

// Create Callable instance to schedule. 
Callable<Void> c = new Callable<Void>() { 
    public Void call() { 
    try { 
    // Do work. 
    } finally { 
    // Reschedule in new Callable, typically with a delay based on the result 
    // of this Callable. In this example the Callable is stateless so we 
    // simply reschedule passing a reference to this. 
    service.schedule(this, 5000L, TimeUnit.MILLISECONDS); 
    } 
    return null; 
    } 
} 

service.schedule(c); 

此方法避免了需要關閉並重新創建ScheduledExecutorService

+0

而不是'Callable '你可以(應該)使用'Runnable'。 – Thirler 2014-11-21 09:56:14

+0

@ Thirler:是的,這是一個公平的觀點。 – Adamski 2014-11-24 14:25:08

+0

我沒有找到ScheduledExecutorService的'schedule(Callable)'函數。只有具有所有參數的那些。你能指點我在哪裏嗎?或者至少修正了示例以包含延遲0. – jlanza 2017-01-31 20:17:48