In the Java6 JDK, file: src/share/classes/com/sun/jmx/remote/internal/ArrayNotificationBuffer.java
void removeSharer(xxx) {
sync(this) {
empty = ...; // set empty=true
} // UNLOCK 'this' - 1
if( empty ) // test empty - 2
dispose(); // call dispose
}
public void dispose() {
synchronized(this) { // RELOCK 'this' - 3
...
}
}
So basically the order of events is:
- 1 : UNLOCK 'this'
- 2 : test empty
- 3 : RELOCK 'this'
If another thread invalidates the 'empty' flag while at step 2 ('this' is unlocked), e.g. by calling addSharer on the same ArrayNotificationBuffer then you end up calling 'dispose()' on a non-empty sharer. Our stress-mode -Xcomp JCK test runs trigger this crash fairly routinely.