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

Will McQueen willmcqueen at yahoo.com
Mon Dec 14 03:34:59 EST 2009


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/365adda8/attachment-0001.html>


More information about the Concurrency-interest mailing list