2011-06-27 54 views
20

對於執行週期任務,我看着TimerScheduledThreadPoolExecutor(通過單個線程),並決定使用後者,因爲在reference for Executors.newSingleThreadScheduledExecutor(),它說:爲什麼ScheduledExecutorService在拋出異常後不能再次運行任務?

不過請注意,如果這個單一線程終止由於在關機之前的執行過程中出現故障,如果需要執行後續任務,則會取代它。

我的計劃是將此用作防範未監測到的一段代碼中的未捕獲異常,以監控其他操作。我想確認並寫下下面的測試,並立即失敗。看來我在做錯誤的假設,或者對我的測試錯誤?

下面的代碼:

@Test 
public void testTimer() { 
    final AtomicInteger cTries = new AtomicInteger(0); 
    final AtomicInteger cSuccesses = new AtomicInteger(0); 

    TimerTask task = new TimerTask() { 
     @Override 
     public void run() 
     { 
      cTries.incrementAndGet(); 
      if (true) { 
       throw new RuntimeException(); 
      } 
      cSuccesses.incrementAndGet(); 
     } 
    }; 

    /* 
    Timer t = new Timer(); 
    t.scheduleAtFixedRate(task, 0, 500); 
    */ 
    ScheduledExecutorService exe = Executors.newSingleThreadScheduledExecutor(); 
    exe.scheduleAtFixedRate(task, 0, 500, TimeUnit.MILLISECONDS); 
    synchronized (this) { 
     try { 
      wait(3000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 
     } 
    } 
    exe.shutdown(); 
    /* 
    t.purge(); 
    */ 
    Assert.assertEquals(cSuccesses.get(), 0); 
    Assert.assertTrue(cTries.get() > 1, String.format("%d is not greater than 1. :(", cTries.get())); 
} 
+0

我知道,我可以圍繞東西包裹一個(可扔),但我的計劃是以某種方式保護我自己。 –

+5

對於像這樣的框架代碼來說,假設它可以安全地重新啓動失敗的作業會有問題 - 事件發生失敗並出現異常意味着數據可能已經保留在任何狀態,並且可能會重新啓動工作。 –

+3

關於啓動新線程的引用是允許其他作業繼續運行,即使其中一個失敗 –

回答

22

一旦重複任務已經拋出未捕獲的異常假設錯誤狀態已去世或已定。除非您檢查Future以獲取錯誤/異常,否則它會自動失敗。

如果您不想殺死重複任務,則必須捕捉異常。


馬特b在上面的評論指出,

這將是一個框架的代碼有問題這樣的假設它可以安全地重新啓動失敗的任務 - 事實上,它失敗異常意味着數據可能已經處於任何狀態,並且可能重新啓動作業可能不安全。

+0

這是否仍適用?在Spring boot 1.5.3中,重複任務的默認錯誤處理程序是[LOG_AND_SUPRESS_ERROR_HANDLER](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/support/TaskUtils.html# LOG_AND_SUPPRESS_ERROR_HANDLER),它不會從執行隊列中刪除@Scheduled。 –

+0

我同意編程代碼以忽略異常並自動重新啓動是個壞主意,但是我可以編程一個REST式服務,我可以使用它重新啓動計劃程序,一旦我手動解決問題時? – jDub9

+0

@ jDub9你可以。當您準備再次運行時,創建新的ExecutorService或新任務沒有任何問題。 –

5

matt b已經給出了原因。

這將是一個框架的代碼有問題這樣的假設它可以 安全地重新啓動失敗的任務 - 它失敗的 例外的事實意味着數據可能已經被留在任何類型的 狀態,並且可能重新啓動該作業將是不安全的。



應當注意的是,寫的ScheduledExecutorService

的文檔中。如果任務的任一執行遇到異常,隨後 執行被抑制。

而作爲邁克爾Krusse說,有關創建一個新的線程點是爲了讓其他任務繼續運行。

相關問題