[concurrency-interest] Are synchronized methods safer than synchronized blocks?

David Holmes davidcholmes at aapt.net.au
Mon Dec 14 03:55:46 EST 2009


Hi Will,

The issue you raise with synchronized blocks is addressed through a somewhat
controversial mechanism whereby the catch-all block that does the
monitorExit acts as its own exception-handler, so if that second exception
occurs then the monitorExit will be attempted again. This has a consequence
that if monitorExit itself throws an exception then you tend to enter an
infinite loop - either continually throwing the exception, or else from the
second attempt throwing IllegalMonitorStateException because the monitor was
released prior to the first exception being thrown. But you are at least
guaranteed not to be able to leave the synchronized block without releasing
the monitor.

See
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4414101

and related CRs for some discussion.

In relation to use Lock/Condition vs inbuilt. Yes asynchronous exceptions
can break things.

But note that asynchronous exceptions can break just about any Java code. So
avoiding synchronized blocks and Locks/Conditions to get some perceived
protection from asynchronous exceptions is misguided and futile. If
asynchronous exceptions can happen in all but the most trivial of code then
you are up the proverbial creek without a paddle.

Cheers,
David Holmes
  -----Original Message-----
  From: concurrency-interest-bounces at cs.oswego.edu
[mailto:concurrency-interest-bounces at cs.oswego.edu]On Behalf Of Will McQueen
  Sent: Monday, 14 December 2009 6:35 PM
  To: concurrency-interest at cs.oswego.edu
  Subject: [concurrency-interest] Are synchronized methods safer
thansynchronized blocks?


        Hi,

        Are synchronized methods safer than synchronized blocks, in terms of
guaranteeing that any monitors held by a thread will be released before that
thread dies?


        My understanding is this:

        1) The monitor that is acquired when a thread enters a synchronized
instance *method* or synchronized static *method* is guaranteed to be
released when the method's frame is popped off that thread's stack (provided
only that the JVM doesn't crash). That is, the monitor is absolutely
guaranteed to be released when the method returns, whether it returned
normally, or abnormally (via thrown exception). With synchronized methods,
the JVM acquires/releases the monitor on behalf of the thread, since there
are no corresponding monitorenter/monitorexit bytecodes for synchronized
methods (only for synchronized blocks).

        2) A synchronized *block* compiles into Java bytecodes in which a
catch-all catch clause (inserted by the compiler) catches any thrown
exception (a Throwable?). This compiler-generated catch clause calls
'monitorexit' and then rethrows the exception with 'athrow'.



        On p508 of "Inside the Java Virtual Machine, 2nd ed" [Venners], it
says "No matter how the synchronized block is exited, the object lock
acquired when the thread entered the block will definitely be released". I'm
not so sure about that, but I'm hoping to be proven wrong. I believe that
using a synchronized block results in a weaker guarantee of releasing a
monitor than when using a synchronized method. For example:

        Suppose I have an application with 2 threads, T1 and T2. Then
suppose:
        1) T1 enters a synchronized block:
            public static final Object lock = new Object();
            ...
            public void foo() {
                synchronized(lock) {
                    ... //T1 is currently executing here
                }
            }

        2) T2 calls foo(), and blocks waiting for T1 to exit the monitor
associated with the object whose reference is stored in var 'lock'.

        3) While T1 is executing within the synchronized block, the JVM
causes an Error or RuntimeException to be thrown from T1 (or, we can think
of some 3rd thread calls Thread.stop on T1, causing a ThreadDeath exception
to be thrown from T1... I know Thread.stop is deprecated and unsafe, but I
mention it as an analog to what I expect the JVM is doing). This causes
execution in T1 to jump to the compiler-generated catch clause to begin
execution there. But, just after the catch clause is entered, and before the
monitorexit instr is executed, let's say that the JVM causes another Error
or RuntimeException to be thrown from T1. So, this 2nd exception would cause
immediate exit from the catch clause before the monitorexit instr has
executed, correct? The exception continues propagating up the stack until
thread T1 dies. In that case, I imagine that T2 would be deadlocked, waiting
forever on a monitor that can never be released since the owner is now dead.


        If the above is true, then I would conclude that:
        1) I should favor synchronized methods over synchronized blocks,
especially in critical systems where deadlock must absolutely be avoided.
        2) By extension, I should favor synchronized methods over Java 1.5's
Lock class (where the Lock object's unlock() method must be called in a
finally clause that is also susceptible to the '2nd exception' issue).


        Thoughts, comments, and corrections are greatly appreciated.

        Thank you.

        Cheers,
        Will


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20091214/81ce132e/attachment.html>


More information about the Concurrency-interest mailing list