2012-11-15 60 views
1

我在調查的一些開源代碼中遇到以下情況。它使用一個synchronized塊,其執行以下操作:Java同步塊內的意外狀態

  1. 設置一個私有布爾實例變量hasListener真
  2. 來電,做一些wait()的周圍有一個大try塊存儲任何異常荷蘭國際集團的方法一個實例變量內部
  3. 套hasListener爲false
  4. 拋出先前存儲

有在同一類中的另一類似方法,該方法不正是在S的任何異常阿米的東西。

從理論上講,這應該確保hasListener在您輸入時只有虛假。然而,以某種方式,底部引發了一個異常(請參閱標記爲//的註釋),因爲它進入方法並且hasListener爲true。我已經檢查過沒有其他地方設置了hasListener,並且默認值爲false。在waitFirstMessage()的底部引發異常會阻止變量被設置爲false嗎?任何其他可能的情況?

從日誌中看,似乎發生了一個合法的異常(「超出完成操作的時間」),並且從此異常(//?)被拋出的頻率相當高。

protected void waitFirstMessage (int msgId) throws LDAPException { 
    synchronized (this) { 
     if (!hasListener) { 
      hasListener = true; 
      while ((request != null) && (request.id == msgId) && 
       (m_exception == null) && (response == null)) { 
       waitForMessage(); 
      }   
      hasListener = false; 
      // Network exception occurred ? 
      if (m_exception != null) { 
       LDAPException ex = m_exception; 
       m_exception = null; 
       throw ex; 
      } 
     } else { 
      //? 
      throw new LDAPException(); 
     } 
    } 
} 

private void waitForMessage() throws LDAPException { 
    try { 
     if (request.timeToComplete > 0) { 
      long timeToWait = request.timeToComplete - 
       System.currentTimeMillis(); 
      if (timeToWait > 0) { 
       wait(timeToWait); 
       if (notified) { 
        notified = false; 
       } else if (request.timeToComplete < System.currentTimeMillis()) { 
        // Spurious wakeup before timeout. 
        return; 
       } else { 
        request = null; 
        m_exception = new LDAPException(
         "Time to complete operation exceeded", 
         LDAPException.LDAP_TIMEOUT); 
       } 
      } else { 
       request = null; 
       m_exception = new LDAPException(
        "Time to complete operation exceeded", 
        LDAPException.LDAP_TIMEOUT); 
      } 
     } else { 
      wait(); 
      notified = false; 
     } 
    } catch (InterruptedException e) { 
     m_exception = new LDAPInterruptedException("Interrupted LDAP operation"); 
    } catch (Exception e) { 
     m_exception = new LDAPException("Unexpected exception while waiting for response", 
      LDAPException.OTHER, e.getMessage()); 
    } 
} 

編輯

好吧,事實證明,我的問題是不正確的。當前在生產中運行日誌的版本比我正在查看的代碼稍早,並且有人明確地解決了這個問題。在以前的版本中waitForMessage()方法拋出異常。這些打斷了waitFirstMessage(int msgId),然後hasListener從未被設置爲false。宇宙再次合理。

非常感謝回覆。現在我需要將此修復程序投入生產!

+0

只是爲了確定...(1)'hasListener'沒有在'synchronized'塊之外的其他方法中設置嗎?和(2)'hasListener'不是'static'? –

+0

不是它不是'靜態'。它被初始化爲false,唯一設置的地方就是上面的方法,而另一個地方它完全一樣。 –

回答

0

如果waitForMessage通過拋出異常突然完成,將不會達到。如果此代碼旨在確保hasListener = false已執行,則應將其放入finally塊中。

0

hasListenerwaitForMessage拋出的情況下將被設置爲true。由於waitForMessage捕獲所有的異常,這可能是恕我直言,當某些東西被拋出,但不是例外(一些其他的Throwable),或者如果在m_exception的安裝期間拋出異常。

+0

感謝您的指點,我會查看一些投擲Throwable看是否是這種情況 –