在我正在调查的一些开源代码中,我遇到了以下情况。它使用了一个同步块,它执行以下操作:
- 将私有布尔实例变量 hasListener 设置为 true
- 调用一个方法,该方法使用一个大的 try 块来执行一些 wait() 操作,该块将任何异常存储在实例变量中
- 将 hasListener 设置为 false
- 抛出以前存储的任何异常
在同一个类中还有另一个类似的方法,它做的事情完全相同。
从理论上讲,这应该确保 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
非常感谢您的回复。现在我需要将此修复程序投入生产!