2011-07-12 122 views
7

這個片段是從JCIP(作者Brian Goetz)上市6.15爲什麼恢復線程池中的線程

f.get跑(任務的中斷標誌)拋出InterruptedException的和爲ExecutionException。現在,這些例外情況對未來是否正確? 意味着未來所代表的具體任務被打斷或出現內部異常。

問題 -

  1. 爲什麼我需要恢復使用中斷 「Thread.currentThread()中斷()。」? ,因爲我的任務運行的線程不是中斷標誌嗎?這有點令人困惑。

  2. 爲什麼拋出launderThrowable異常?如果其中一個downloadImage存在問題,我們是不是應該只處理其他下載的圖像,而不是處理剩下的未來?

    package net.jcip.examples; 
    
    import java.util.*; 
    import java.util.concurrent.*; 
    import static net.jcip.examples.LaunderThrowable.launderThrowable; 
    
    /** 
    * Renderer 
    * <p/> 
    * Using CompletionService to render page elements as they become available 
    * 
    * @author Brian Goetz and Tim Peierls 
    */ 
    public abstract class Renderer { 
        private final ExecutorService executor; 
    
        Renderer(ExecutorService executor) { 
         this.executor = executor; 
        } 
    
        void renderPage(CharSequence source) { 
         final List<ImageInfo> info = scanForImageInfo(source); 
         CompletionService<ImageData> completionService = 
           new ExecutorCompletionService<ImageData>(executor); 
         for (final ImageInfo imageInfo : info) 
          completionService.submit(new Callable<ImageData>() { 
           public ImageData call() { 
            return imageInfo.downloadImage(); 
           } 
          }); 
    
         renderText(source); 
    
         try { 
          for (int t = 0, n = info.size(); t < n; t++) { 
           Future<ImageData> f = completionService.take(); 
           ImageData imageData = f.get(); 
           renderImage(imageData); 
          } 
         } catch (InterruptedException e) { 
          Thread.currentThread().interrupt(); 
         } catch (ExecutionException e) { 
          throw launderThrowable(e.getCause()); 
         } 
        } 
    
        interface ImageData { 
        } 
    
        interface ImageInfo { 
         ImageData downloadImage(); 
        } 
    
        abstract void renderText(CharSequence s); 
    
        abstract List<ImageInfo> scanForImageInfo(CharSequence s); 
    
        abstract void renderImage(ImageData i); 
    
    } 
    

回答

1
  1. 中斷不一定發生在線程池的線程上。當你在等待未來的完成時,當前的線程被中斷時,中斷是一個點。例如,如果您讓Future的其他部分可以取消下載,則Future.cancel(true)將導致發生InterruptedException,然後您可以清除其餘的數據。正如Beohemaian所說,傳播中斷總是安全的。

  2. 這是一個很好的問題。我認爲這更像是他希望做的事情的設計選擇。但是,您可以輕鬆地堅持該錯誤並在完成其餘部分後拋出該錯誤。有些事情要考慮,但如果它是一個OutOfMemoryError呢?然後,如果它的一個錯誤,也許不是一個RuntimeException,那麼洗滌程序將會很有用。

+0

'錯誤'應該是不可恢復的東西。 'StackOverflowError'如何?堆棧可能已損壞。 'InternalError'如何?它的虛擬機狀態已損壞。你不能抓住他們。 –

+0

是的你是對的。那是我用OutOfMemoryError去的地方。儘管清洗方法也會重新拋出運行時異常(至少在本例中) –

2

通過捕獲InterruptedException,你到達中正在運行的線程停止中斷。但是你希望它能夠達到它,以防在中斷的情況下線程需要做特殊處理 - 你不能說出來,所以你最好安全地玩它,讓它滲透。你可以自己做一些處理(清理,退出你在做什麼等),但你必須傳遞它。最好的方法是致電Thread.currentThread().interrupt()

3

當你捕獲InterruptedException中斷標誌得到重置,你的線程在技術上不再中斷。但是,您不知道調用代碼的代碼(或同一線程中的其他代碼)是否需要額外的中斷處理。通過調用interrupt(),您再次提升標誌,並有效地對應用程序的其餘部分說:「該線程仍然中斷 - 如果需要的話執行該線程」。

考慮一下例子。你的方法是從循環中調用的,如果線程中斷,它必須終止。你發現了這個異常,如果你不提升這個標誌,循環將不會按需要終止。

+0

只需添加更多細節:當Java庫中的某些阻塞方法拋出一個'InterruptedException'時,線程的中斷標誌將重置爲false。檢查例如['Thread.sleep()']的文檔(http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#sleep%28long%29)或['的Object.wait()'](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#wait%28%29) –