2013-06-19 17 views
0

該方案如下。正確處理InterruptedException異常的方法,當實現不拋出它的接口時

我實現一個接口,閱讀這樣的:

public interface MessageSourceProvider 
{ 
    MessageSource getMessageSource(Locale locale); 
} 

有此接口的兩個實現:一個從靜態的來源,這是在「構造時間」完全初始化讀取,並且其中一個沒有;後者的實現是這樣的(expiryEnabled是一個AtomicBoolean;註釋去掉,完整的源here; sourcesMap<Locale, FutureTask<MessageSource>>):

@Override 
public MessageSource getMessageSource(final Locale locale) 
{ 
    if (!expiryEnabled.getAndSet(true)) 
     setupExpiry(expiryDuration, expiryUnit); 

    FutureTask<MessageSource> task; 

    synchronized (sources) { 
     task = sources.get(locale); 
     if (task == null || task.isCancelled()) { 
      task = loadingTask(locale); 
      sources.put(locale, task); 
      service.execute(task); 
     } 
    } 

    try { 
     final MessageSource source = task.get(timeoutDuration, timeoutUnit); 
     return source == null ? defaultSource : source; 
    } catch (InterruptedException ignored) { 
     Thread.currentThread().interrupt(); // <-- HERE 
     return defaultSource; 
    } catch (ExecutionException ignored) { 
     return defaultSource; 
    } catch (TimeoutException ignored) { 
     task.cancel(true); 
     return defaultSource; 
    } catch (CancellationException ignored) { 
     return defaultSource; 
    } 
} 

由於接口本身不聲明拋出InterruptedException(因爲一些實現永遠不會這麼做),我做Thread.currentThread.interrupt()。我這樣做是爲了符合界面。反過來,這個接口的實現方式被用作諸如在「主」,用戶交互類:​​現在

public String getMessage(final Locale locale, final String key) 
{ 
    BUNDLE.checkNotNull(key, "query.nullKey"); 
    BUNDLE.checkNotNull(locale, "query.nullLocale"); 

    String ret; 
    MessageSource source; 

    for (final Locale l: LocaleUtils.getApplicable(locale)) 
     for (final MessageSourceProvider provider: providers) { 
      source = provider.getMessageSource(l); 
      if (source == null) 
       continue; 
      ret = source.getKey(key); 
      if (ret != null) 
       return ret; 
     } 

    // No source found which has the key... Return the key itself. 
    return key; 
} 

,問題是與FutureTask。由於.get()處於阻塞狀態,因此可能會引發InterruptedException。並且由於基本接口沒有聲明拋出異常,所以如果我找到一個,我選擇恢復線程中斷狀態。

然而,文獻並不認同:它表示只有在您自己創建的Thread範圍內,您才應該這麼做,或者忽略該例外。

我的問題是:這是一個面向API的用戶,我目前處理這個問題的方式是否存在潛在的問題?如果是的話,我該如何解決?

+0

你提到的任何文獻都是_wrong_。你的處理是正確的。 – jtahlborn

+0

@jtahlborn這是JCIP。但是也許我對JCIP所說的內容的解釋是錯誤的。事實上,這很可能。 – fge

+0

它在哪裏說你不應該永久中斷狀態? (手邊沒有這本書)。 – jtahlborn

回答

3

現在,問題在於FutureTask。由於.get()被阻塞,因此可能會拋出InterruptedException。並且由於基本接口沒有聲明拋出異常,所以如果我找到一個,我選擇恢復線程中斷狀態。

這是完全正確的。你應該總是這樣做。

try { 
    ... 
} catch (InterruptedException e) { 
    // InterruptedException clears interrupt flag 
    // I always re-interrupt the thread first 
    Thread.currentThread().interrupt(); 
    // then i decide if I want the thread to return or throw or ... 
    return; 
} 

我還會說,你應該考慮一下你的線程被中斷的意思。有人中斷了名爲future.get()的線程。該線程應該如何響應?

  • 它應該拋出一個RuntimeException
  • 它應該停止做它正在做什麼,並退出?
  • 它應該關閉線程池嗎?

文學,但是,不同意:它說,你應該只做到這一點,或者忽略了的異常,只有你是你自己創建一個線程中的事件。

我不確定您正在查看哪些文獻,但海事組織不正確或不準確。例如,

+0

我所指的文獻實際上是JCIP。也許我正在考慮這裏說的有點太認真...... – fge

+1

我記得,JCIP說拋出是處理這個問題的最簡單的方法。 –

1

恢復中斷標誌是完全合法的,如中的Java併發實踐中所討論的。

+0

是的,它是JCIP,並從codereview.stackexchange.com發表評論,這促使我這樣做......然而,同一本書說最好的方法是把它扔回去,這是我在這裏買不起的:/ – fge

相關問題