2013-10-07 54 views
0

我正在集成一個我無法控制的遺留庫。如何處理失敗的期貨

它具有以下接口中定義:

interface Factory { 
    Future<Void> subscribe(Context c); 
} 

此「訂閱」方法經常與不同線程調用。當我關心「Future.get()」的結果時唯一的情況是失敗時,我可以獲取並處理異常。這不必在調用線程中發生。另外,在我的情況下,阻止「Future.get()」上的調用線程可能會非常昂貴,因爲即使成功完成也可能需要幾秒鐘才能完成填充。

所以我的任務是以某種方式「後處理」所有這些未來,過濾失敗的。基本上,我可以看到兩種可能的方法:

方法1:

在獲得未來的一個實例,提出獨立的Runnable外部執行程序,它會做必要的:

executor.submit(
     new Runnable(){ 
      @Override 
      public void run() { 
       try { 
        future.get(); 
       } catch(Exception e){ 
        // process the exception 
       } 
      } 
     } 
    ); 

缺點這種方法是我們仍然在一段時間內阻塞線程。正如我所說的,這段代碼將會被頻繁執行。

方法2:

在獲得未來的一個實例,其放置一些收集和奉獻一個獨立的單一線程將定期通過做處理這個集合的元素運行:

while(true){ 
     Iterator<Future<Void>> iterator = collection.iterator(); 
     while(iterator.hasNext()){ 
      Future<Void> future = iterator.next(); 
      if(future.isDone()){ 
       try { 
        future.get(); 
       } catch(Exception e){ 
        // process the exception 
       } finally { 
        iterator.remove(); 
       } 
      } 
     } 

     TimeUnit.MILLISECONDS.sleep(1000); // sleep 
    } 

你怎麼看?有沒有更好的方法來解決這個問題?

回答

1

由於您沒有手動創建Future最佳選項不可用,請使用自定義FutureFuture本身觸發處理。

所以在你的情況下,我建議一個模式,可能看起來像你的兩個選項的混合物。將Future添加到(線程安全)隊列,並將Runnable s提交給處理循環中所有項目的執行程序。所以你可以通過配置Executor來限制線程的數量,也就是說沒有像Future那樣多的線程,但仍然可以有多個線程,並且不必一直保持這些後處理線程的活動狀態。

爲了避免無限循環時重新排隊未完成項目,使用一個本地集合以分離從重新排隊項未決:

static BlockingQueue<Future<?>> PENDING = …; 
static int MAX_ITEMS_PER_JOB = …; 
… 
/*scheduling code …*/new Runnable() { 
    public void run() 
    { 
    ArrayList<Future<?>> myLocalItems=new ArrayList<>(); 
    PENDING.drainTo(myLocalItems, MAX_ITEMS_PER_JOB); 
    for(Future<?> f:myLocalItems) { 
     if(!f.isDone()) PENDING.offer(f); // re-queue 
     try { 
     f.get(); 
     } catch(ExecutionException ex) { 
     handleException(ex.getCause()); 
     } 
    } 
    } 
}; 

所以這Runnable將檢查和處理的Future有限數量的然後返回,所以如果有很多項目正在等待處理,那麼適合多次提交併行處理,但如果較少數量處於待處理中,則不會造成任何損害,因爲如果沒有任何關係,作業不會掛起。它們甚至適用於使用ScheduledExecutorServicescheduleWithFixedDelay