2017-01-10 26 views
1

我試圖解決類似於通過郵件客戶端從郵件服務器下載新郵件的問題。我有一個任務,定期執行(例如,下一次迭代是在最後一個結束後10分鐘),但也可以手動運行任務。在Java中處理可能的手動啓動的定期作業

當我嘗試手動運行作業並且此時沒有運行作業(稍後被指定)時,我暫時取消預約並安排它。當作業已經運行時,我不會取消它,但請等到它完成並再次運行。但是隻有一個任務可以這樣等待。

我的問題是,我不知道如何同步作業,使其線程安全,並確保作業永遠不會同時運行兩次。

爲了更清楚。主要的問題是簡單的詢問工作是否正在進行,並根據我得到的結果做出決定是不夠的,因爲問題和行動之間的情況可能會改變。這是一個短的跨度,但概率不是零。同樣的問題在於決定是否應該在他的跑步結束時再次執行這項工作。如果我的決定是基於某個變量或某個其他if子句的值,那麼在測試其值和執行一些操作之間,其他某個線程可以更改它,最終可以完成兩個計劃任務或完全沒有任何任務。

回答

0

您是否考慮過使用DelayQueue

要讓你的工作運行now你只需要說服它返回0表格getDelay(TimeUnit unit)

+0

我不明白怎麼能這樣幫助。我可以要求獲得隊列的頭部,但在某些情況下,我可以得到空值,因爲getDelay返回一毫秒,當我根據這個決定做出決定時,它會中斷,因爲我會預期它不會運行並運行它,導致它會運行兩次。 –

+0

您可以編寫自己的[延遲](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Delayed.html)並將其放入隊列中。然後你可以在外部操作它使其返回'0'。 – OldCurmudgeon

0

做檢查您所講述的主要方法是檢查,鎖和後重複相同的檢查

public class OneQueuedThread extends Thread { 
    static int numberRunning =0; 
    public void run() { 
     if (numberRunning<2) { 
      synchronized (OneQueuedThread.class){ 
       if (numberRunning<2) { 
        numberRunning++; 
        // ---------------your process runs here 
        numberRunning--; 
       } 
      } 
     } 
    } 
} 

所以,只有一種嘗試運行線程而它已經運行的時候會等到運行線程結束並開始運行。

至於調度,讓我們使用TimerTask的特點:

 public class ScheduledTask extends TimerTask { 
     ScheduledTask instance; 


     /** 
     * this constructor is to be used for manual launching 
     */ 
     public void ScheduledTask(){ 
      if (instance == null){ 
       instance = this; 
      } else { 
       instance.cancel(); 
      } 
      instance.run(); 
     } 

     /** 
     * This constructor is to be used for scheduled launching 
     * @param deltaTime 
     */ 
     public ScheduledTask(long deltaTime){ 
      instance = this; 
      Timer timer = new Timer(); 
      timer.schedule(instance, deltaTime); 

     } 

     public void run() { 
      OneQueuedThread currentTread; 
      currentTread = new OneQueuedThread(); 
      currentTread.start(); 
     } 
    }