We hit an extremely surprising exception today. Inside of a synchronized block, we call wait() and it throws IllegalMonitorStateException
. What can cause this?
This is happening in well-tested open source code: http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java?view=markup#l222
We eliminated the obvious causes:
muxLock
muxLock
is finalSo, I'm trying to think of more far-fetched explanations.
UPDATE: (based on comment)
I've also verified from the stacktrace and breakpoint that the thread is indeed inside the synchronized block when the exception is thrown. It's not the case that some other unrelated code is emitting the exception (unless something is REALLY confusing Eclipse!)
The IllegalStateException is thrown when the Java environment or application is not in an appropriate state for the requested operation. This can occur when dealing with threads or the Collections framework of the java.
wait() , this call must be placed in synchronized block, otherwise an IllegalMonitorStateException is thrown.
Class IllegalMonitorStateException Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.
The only suspicious thing I see that you are passing a reference to 'this' to some other object in your constructor. Is it possible (in fact, not unlikely) that, through weird re-ordering of things, if some other thread gets that reference to 'this' and calls the method that uses the muxlock, things can go extremely wrong.
The Java Language Specification is pretty specific about this:
An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.
In other words, if another thread gets hold of the 'this' reference before the constructor is finished, the final field 'muxlock' might not be correctly initialized yet. In general, publishing a reference to 'this' before the constructor has finished can be pretty dangerous, especially in threaded situations.
Some potentially useful discussion about such things: http://madpropellerhead.com/random/20100328-java-final-fields-are-not-as-final-as-you-may-think
For some older, but still useful general discussion of why publishing 'this' in a constructor is a very bad idea in general, see for instance: http://www.ibm.com/developerworks/java/library/j-jtp0618/index.html
http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java?r1=1069292&r2=1135026&diff_format=h
here i can see that timeout was added lately
make sure that startTimeout is > than 0 otherwise you will wait(0) or wait(-n) this probably cause IllegalMonitorStateException
EDIT: Ok above is a disaster But lets try this :
we are in Mux constructor : http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java?view=markup
line 176 we create SocketChannelConnectionIO andd pass this after that we break and and different thread takes over .
in constructor of SocketChannelConnectionIO defined here : http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/jeri/internal/mux/SocketChannelConnectionIO.java?view=markup line 112 we register to channel with the new handler().
handler recieaves something on chanel and function let say function handleReadReady is executed we synchronize on muxLock .
now we are still in constructor so object in final is still mutable !!! let assume it changes , now we have something waiting on different muxLock
One in a million scenario
EDIT
http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/jeri/internal/mux/Mux.java?revision=1135026&view=co
Mux(SocketChannel channel, int role, int initialInboundRation, int maxFragmentSize) throws IOException { this.role = role; if ((initialInboundRation & ~0x00FFFF00) != 0) { throw new IllegalArgumentException( "illegal initial inbound ration: " + toHexString(initialInboundRation)); } this.initialInboundRation = initialInboundRation; this.maxFragmentSize = maxFragmentSize; //LINE BELOW IS CAUSING PROBLEM it passes this to SocketChannelConnectionIO this.connectionIO = new SocketChannelConnectionIO(this, channel); //Lets assume it stops here we are still in constructor //and we are not in synchronized block directBuffersUseful = true; }
now in constructor of SocketChannelConnectionIO http://svn.apache.org/viewvc/river/jtsk/trunk/src/com/sun/jini/jeri/internal/mux/SocketChannelConnectionIO.java?revision=1069292&view=co
SocketChannelConnectionIO(Mux mux, SocketChannel channel) throws IOException { super(mux); channel.configureBlocking(false); this.channel = channel; //Line below we are registering to the channel with mux that is still mutable //this is the line that actually is causing the problem move that to // start() and it should work key = selectionManager.register(channel, new Handler()); }
move this code to start() should work key = selectionManager.register(channel, new Handler());
(i am assuming start is executet when we want to start prosessing)
/** * Starts processing connection data. */ void start() throws IOException { key = selectionManager.register(channel, new Handler()); key.renewInterestMask(SelectionKey.OP_READ); }
But it would be much better not to create SocketChannelConnectionIO in the constructor of mux but maybe somewhere after that the same for second constructor creating StreamConnectionIO with this
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With