Hi guys,
I ran into the following exception today (using 1.9.3)
java.lang.IllegalMonitorStateException
at
java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:127)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1175)
at
java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:431)
at
com.sun.grizzly.async.AbstractAsyncQueueWriter.onWrite(AbstractAsyncQueueWriter.java:378)
at
com.sun.grizzly.async.AsyncQueueWriterContextTask.doCall(AsyncQueueWriterContextTask.java:86)
at
com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:56)
at
com.colibria.execution.ThreadPoolImplCore$4.call(ThreadPoolImplCore.java:171)
at
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:207)
at
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
The problems seems to be that I'm using the same thread, which call
callbackHandler.onWriteCompleted(), to schedule the next msg to be sent.
Let me explain in more detail:
1. thread1 owns the lock and calls
queueRecord.callbackHandler.onWriteCompleted()
2. the implementation behind this callbackHandler directs thread1 back
to this AbstractAsyncQueueWriter and calls write().
3. thread1 releases the lock in the final-block in this very write()
method without having acquired it for a second time, leaving the lock in
the "unlock" state.
4. while thread1 is still inside the
queueRecord.callbackHandler.onWriteCompleted() method and thinks it
still own the lock thread2 comes along and calls onWrite() and acquires
the lock
5. thread1 returns from the
queueRecord.callbackHandler.onWriteCompleted() method and calls unlock,
which causes the exception.
My first guess for a solution would be to ensure that a lock is always
acquired before given up, instead of always unlocking in the final block.
Not allowing the same thread to call write() again is not really an
options, since creating a new task for each
queueRecord.callbackHandler.onWriteCompleted() call would impact
performance.
What are your thoughts on this?
Thanks
Sebastian