I've got the following situation in some open source code I'm investigating. It is using a synchronised block which does the following:
There is another similar method in the same class which does exactly the same thing.
In theory this should ensure that hasListener is only ever false when you enter. Yet somehow , an exception is being thrown at the bottom (see comment marked //?) because it enters the method and hasListener is true. I've checked that there are no other places where hasListener is set, and the default value is false. Are there any conceivable situations where throwing an exception at the bottom of waitFirstMessage() would prevent the variable being set back to false? Any other possible situations?
From the logs, it looks like a legitimate exception occurs ("Time to complete operation exceeded") and from that point on the exception (//?) is thrown fairly often.
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());
}
}
EDIT
Ok, it turns out that my question was incorrect. The version currently running in production where the logs were coming from is slightly earlier than the code I was looking at and somebody has clearly addressed this very problem. In the previous version the waitForMessage()
method was throwing exceptions. These were interrupting waitFirstMessage(int msgId)
and then hasListener
was never being set to false. The universe makes sense again.
Thanks a lot for the replies. Now I need to get this fix into production!
If waitForMessage
completes abruptly by throwing an exception, hasListener = false
will not be reached. If this code was meant to ensure that hasListener = false
is executed, it should have placed that into a finally
block.
hasListener
would be left set to true in the case where waitForMessage
throws. Since waitForMessage
catches all Exceptions, this could IMHO just be the case when something gets thrown that is not an exception (some other Throwable
), or if an exception is thrown during instatiation of m_exception
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.