RFR: In rare cases, the unlock() on join() might fail, causing an IllegalMonitorStateException

Dr Heinz M. Kabutz heinz at javaspecialists.eu
Thu Feb 25 14:32:38 UTC 2021

On 2021/02/25 14:07, Alan Bateman wrote:
> On Thu, 25 Feb 2021 11:10:41 GMT, kabutz <github.com+332398+kabutz at openjdk.org> wrote:
>> Unlike synchronized/wait, the Condition.await() method does not necessarily reacquire the lock on exit, for example if the thread is stopped or if CTRL+C is caused in jshell. In that case we would enter the finally block without the lock held and unlocking would cause an IllegalMonitorStateException.
>> For example, run the following code from jshell and then press CTRL+C:
>> Object monitor = new Object();
>> for (int i = 0; i < 10_000; i++) {
>>    Thread.startVirtualThread(() -> {
>>      synchronized (monitor) {
>>        try {
>>          monitor.wait();
>>        } catch (InterruptedException ignore) {}
>>      }
>>    });
>> }
>> Thread.startVirtualThread(() -> System.out.println("done")).join();
>> Output is:
>> |  Exception java.lang.IllegalMonitorStateException
>> |        at ReentrantLock$Sync.tryRelease (ReentrantLock.java:175)
>> |        at AbstractQueuedSynchronizer.release (AbstractQueuedSynchronizer.java:1007)
>> |        at ReentrantLock.unlock (ReentrantLock.java:494)
>> |        at VirtualThread.joinNanos (VirtualThread.java:635)
>> |        at Thread.join (Thread.java:2281)
>> |        at Thread.join (Thread.java:2366)
>> |        at (#3:1)
> I'm in two minds about point fixes to improve robustness with Thread.stop. In this case, there are other usages of Condition::await, including some of the blocking queue implementations in j.u.concurrent, that probably have the same issue.
> We want Thread::stop to go away. We terminally deprecated and degraded stop(Throwable) in Java 9 and finally removed the method in a later release, the no-arg Thread::stop needs to go the same way. The first steps for this are in the loom repo in the form of terminal deprecation, not supported for virtual threads, and ThreadGroup::stop degraded to unconditionally throw UOE. We've been hesitant to be move faster as there may be usages in the wild where it is used instead of interrupt as a cancellation mechanism.
> I should also say that debugger support (JDI/JDWP,JVMTI) has the equivalent of stop(Throwable) for "managed" usages of async exceptions. jshell uses a signal interrupt and JDI and maybe it's calling Thread.stop, I need to check that as I can't otherwise explain why you see an issue with ctrl-C in jshell.
Indeed, it is not always trivial changing from synchronized/wait to 
Condition/await because of these subtle differences.
> -------------
> PR: https://git.openjdk.java.net/loom/pull/32

More information about the loom-dev mailing list