1

在我正在调查的一些开源代码中,我遇到了以下情况。它使用了一个同步块,它执行以下操作:

  1. 将私有布尔实例变量 hasListener 设置为 true
  2. 调用一个方法,该方法使用一个大的 try 块来执行一些 wait() 操作,该块将任何异常存储在实例变量中
  3. 将 hasListener 设置为 false
  4. 抛出以前存储的任何异常

在同一个类中还有另一个类似的方法,它做的事情完全相同。

从理论上讲,这应该确保 hasListener 只有在您输入时才为假。然而不知何故,一个异常被抛出底部(见注释标记//?),因为它进入方法并且 hasListener 为真。我检查了没有其他地方设置了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

非常感谢您的回复。现在我需要将此修复程序投入生产!

4

2 回答 2

0

hasListenerwaitForMessage在抛出的情况下将设置为 true 。由于waitForMessage捕获所有异常,恕我直言,这可能只是在抛出不是异常(其他一些Throwable)的东西,或者在m_exception.

于 2012-11-15T22:08:49.553 回答
0

如果waitForMessage通过抛出异常突然完成,hasListener = false将无法到达。如果这段代码是为了确保它hasListener = false被执行,它应该把它放在一个finally块中。

于 2012-11-15T22:05:47.547 回答