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

David Holmes davidcholmes at aapt.net.au
Tue Dec 15 04:19:40 EST 2009


Dmytro,

I was quite surprised to discover this is the case. As always with the VM
there is a very complex story here once you get into the internals. I'm
currently trying to ascertain exactly what the situation is. You might (and
I hope you would) get a different result if you used a bytecode assembler to
issue a monitorexit bytecode rather than using Unsafe.

Thanks for the info.

David Holmes

 -----Original Message-----
From: Dmytro Sheyko [mailto:dmytro_sheyko at hotmail.com]
Sent: Tuesday, 15 December 2009 12:42 AM
To: dholmes at ieee.org; willmcqueen at yahoo.com;
concurrency-interest at cs.oswego.edu
Subject: RE: [concurrency-interest] Are synchronized methods safer
thansynchronized blocks?


  Hi,

  It seems that in practice infinite loop does not occur because monitorexit
(for some reason) does not throw IllegalMonitorStateException.
  The program proves this.

  // test/Main.java
  package test;

  public class Main {

      public static void main(String... args) {
          try {
              new Main().useSynchronizedMethod();
              System.err.println("method ...\tok");
          } catch (Throwable exc) {
              System.err.println("method ...\t" + exc);
          }
          System.err.println();

          try {
              new Main().useSynchronizedBlock();
              System.err.println("block  ...\tok");
          } catch (Throwable exc) {
              System.err.println("block  ...\t" + exc);
          }
          System.err.println();
      }

      void useSynchronizedMethod() {
          System.err.println("before enter\t" + Thread.holdsLock(this));
          internalSynchronizedMethod();
          System.err.println("after  exit\t" + Thread.holdsLock(this));
      }

      private synchronized void internalSynchronizedMethod() {
          System.err.println("after  enter\t" + Thread.holdsLock(this));
          UnsafeMonitor.monitorExit(this);
          System.err.println("before exit\t" + Thread.holdsLock(this));
      }

      void useSynchronizedBlock() {
          System.err.println("before enter\t" + Thread.holdsLock(this));
          synchronized (this) {
              System.err.println("after  enter\t" + Thread.holdsLock(this));
              UnsafeMonitor.monitorExit(this);
              System.err.println("before exit\t" + Thread.holdsLock(this));
          }
          System.err.println("after  exit\t" + Thread.holdsLock(this));
      }

  }

  // test/UnsafeMonitor.java - it has to be in bootclasspath in order to
access Unsafe object.
  package test;

  import sun.misc.Unsafe;

  public class UnsafeMonitor {
      private static final Unsafe unsafe = Unsafe.getUnsafe();

      public static void monitorExit(Object obj) {
          System.err.println("unsafe exit");
          unsafe.monitorExit(obj);
      }

  }

  The output is following

  before enter    false
  after  enter    true
  unsafe exit
  before exit    false
  after  exit    false
  method ...    ok

  before enter    false
  after  enter    true
  unsafe exit
  before exit    false
  after  exit    false
  block  ...    ok

  Regards,
  Dmytro


----------------------------------------------------------------------------
--
  From: davidcholmes at aapt.net.au
  To: willmcqueen at yahoo.com; concurrency-interest at cs.oswego.edu
  Date: Mon, 14 Dec 2009 18:55:46 +1000
  Subject: Re: [concurrency-interest] Are synchronized methods safer than
synchronized blocks?


  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





----------------------------------------------------------------------------
--
  Windows Live Hotmail: Your friends can get your Facebook updates, right
from Hotmail®.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20091215/f44473f8/attachment-0001.html>


More information about the Concurrency-interest mailing list