我正在研究的某些开放源代码中有以下情况。它使用同步块执行以下操作:
将私有布尔实例变量hasListener设置为true
调用一个方法,该方法在其周围有一个很大的try块来执行wait()处理,该try块将所有异常存储在实例变量内
将hasListener设置为false
抛出先前存储的任何异常
同一类中还有另一种类似的方法,它们执行的功能完全相同。
从理论上讲,这应该确保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
块中。