JVM Synchronized Finally Blocks
Asked Answered
U

1

7

Looking at the Java Virtual Machine Specification and compiled code tells us how "synchronized" blocks are implemented in java. The following code:

public void testSync()
{
    Object obj = getSomeObject();
    synchronized (obj) { doSomething(); }
}

...is roughly equivalent to this pseudocode:

public void testSync()
{
    Object obj = getSomeObject();
    Object __temp = obj;
    monitorenter __temp;
    try { doSomething(); }
    finally { monitorexit __temp; }
}

...with one exception.

For some reason, the exception table displays two finally handlers. For example:

  Exception table:
     from    to  target type
        12    20    23   any
        23    25    23   any

The first handler is where I expect it to be, but the second handler is actually for the finally block of the first handler, and if it catches an exception it executes the same handler. You could visualize this poorly in the following way:

try { doSomething(); }
finally { beginTry: try { monitorexit __temp; } finally { goto beginTry; } }

Does anybody know why this is? If it were just the finally block, the second entry in the table would not be there. Besides, I can't see any possible reason for wanting to execute the finally block again if it's already thrown an exception.

Thanks, Brandon

Unloose answered 27/2, 2013 at 20:10 Comment(6)
I guess, thou shalt release the monitor even in the event of an exception.Cuomo
Thou shalt try to release the monitor an infinite number of times, even if it's clear that you won't be able to? Ha!Unloose
When is it clear that you won't be able to? There's an important condition that locks and unlocks are always balanced.Cuomo
@TomHawtin For the record, the situations when the monitorexit instruction throws an exception is documented in the JVM spec: 1) if __temp is null, in which case monitorenter will recursively throw NullPointerExceptions; 2) if this thread is not currently the owner of the monitor, in which case recursively trying again and again to "exit" the monitor is not going to help at all; 3) if the monitor has no current owner, which has the same problem. Therefore, if it throws an exception once, it's going to throw it again, an infinite number of times.Unloose
Those aren't the only exceptions. See section 2.10 (in JLS for Java SE 7). And even if they were, continuing execution of the thread outside the synchronized block would be incorrect.Cuomo
@TomHawtin I agree that the execution should stop; I'm just saying that if it doesn't exit the monitor the first time around, it's definitely not going to. (Even according to §2.10, the only other (applicable) ways an exception can be thrown is when you're out of a resource, or when an internal JVM error occurs. Retrying the operation fixes neither of these problems.)Unloose
P
2

If it's a choice between trying over and over to release the monitor unsuccessfully, and proceeding without releasing it, both alternatives will cause a deadlock; just if you proceed without releasing then the deadlock doesn't happen until the next time something tries to acquire the monitor, and that problem may be far away from the initial failure. Also trying to release the monitor may work out eventually, while letting the monitor go unreleased is a certain disaster. So you're better off retrying.

Pareto answered 27/2, 2013 at 20:26 Comment(3)
When you put it this way, it makes much more sense. I guess I was just in the wrong mindset. Thanks!Unloose
@aboveyou00: it does make you think. must be fun to implement this stuff knowing it has to work on all kinds of processors.Pareto
Yes, put this way, even an infinite loop is better than leaving the monitor unreleased.Flittermouse

© 2022 - 2024 — McMap. All rights reserved.