views:

178

answers:

3

Recently I attended a lecture concerning some design patterns:

The following code had been displayed:

public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {      //1
      Singleton inst = instance;         //2
      if (inst == null)
      {
        synchronized(Singleton.class) {  //3
          inst = new Singleton();        //4
        }
        instance = inst;                 //5
      }
    }
  }
  return instance;
}

taken from: Double-checked locking: Take two

My question has nothing to do with the above mentioned pattern but with the synchronized blocks:

Is there any benefit whatsoever to the double synchronization done in lines 1 & 3 with regards to the fact that the synchronize operation is done on the same Object?

+5  A: 

In the old Java Memory Model (JMM), exiting a synchronized block allegedly flushed local data out to main memory. Entering a synchronized block used to cause rereading of cached data. (Here, cache includes registers with associated compiler optimisations.) The old JMM was broken and not implemented correctly.

In the new JMM it doesn't do anything. New JMM is specified for 1.5, and implemented for the "Sun" 1.4 JRE. 1.5 completed it's End of Service Life period some time ago, so you shouldn't need to worry about the old JMM (well, perhaps Java ME will do something unpredictable).

Tom Hawtin - tackline
ok... could you elaborate please? I still can't seem to get the usefulness of the above.
Yaneeve
AFAIK synchronization still does some flushing. (see http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization)
Jens Schauder
Oh, I just realized you were talking about EXITING. Missed that
Jens Schauder
@Jens The new JMM tends to be implemented with some flushing, but it's not part of the model. Nested locking does not cause *happens-before* relationships.
Tom Hawtin - tackline
I am sorry to say that I am still a bit confused... but since the public prefers this answer and since what I can make out is that the double synchronization in the current JMM means nothing I will accept this answer. Cheers
Yaneeve
+2  A: 

I am no memory model expert, but I think one must consider that a "synchronized" doesn't only signal the need to obtain a lock, but also rules about possible optimization of code and flushing and refreshing of caches.

You'll find the details in the Java Memory Model

Jens Schauder
The new Java Memory Model does not concern itself with flushing of caches. It uses *happens-before* relationships which at rather different.
Tom Hawtin - tackline
Hmm, but in order to ensure such a relationship, flushing of cashes has to take place. Or at least so I thought. Can you point me to a resource, explaining the difference/relationship?
Jens Schauder
+2  A: 

Synchronizing twice on the same object does enforce that all of the changes made inside the inner block is flushed shared memory when the inner synchronization block is exited. But what is important to note is that there is no rules that say that changes made after the inner synchronization block can't be made before the inner synchronization is exited.

For example

public void doSomething()
{
  synchronized(this) { // "this" locked
    methodCall1();
    synchronized(this) {
      methodCall2();
    } // memory flushed
    methodCall3();
  } // "this" unlocked and memory flushed
}

Can be compiled to execute in this order

public void doSomething()
{
  synchronized(this) { // "this" locked
    methodCall1();
    synchronized(this) {
      methodCall2();
      methodCall3();
    } // memory flushed
  } // "this" unlocked and memory flushed
}

For a more detailed explanation check out Double Check Locking in the A fix that doesn't work section about a third of the way down.

Yanamon