繁体   English   中英

Java同步块内的意外状态

[英]Unexpected state inside Java synchronized block

我正在研究的某些开放源代码中有以下情况。 它使用同步块执行以下操作:

  1. 将私有布尔实例变量hasListener设置为true
  2. 调用一个方法,该方法在其周围有一个很大的try块来执行wait()处理,该块将任何异常存储在实例变量内
  3. 将hasListener设置为false
  4. 抛出先前存储的任何异常

同一类中还有另一种类似的方法,它们执行的功能完全相同。

从理论上讲,这应该确保hasListener仅在您输入时为false。 然而, 不知何故 ,底部将引发异常(请参见标记为//?的注释),因为它进入方法并且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。 宇宙再次有意义。

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

如果waitForMessage通过引发异常突然完成,则将不会到达hasListener = false 如果此代码旨在确保已执行hasListener = false ,则应将其放入finally块中。

hasListener将留待设置为true在的情况下waitForMessage抛出。 由于waitForMessage捕获了所有异常,因此,当抛出不是异常(某些Throwable )的异常或在m_exception实例化期间引发异常时,恕我直言。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM