Double-checked locking

The DCL idiom was designed to support lazy initialization, which occurs when a class defers initialization of an owned object until it is actually needed:

public class WorldCup {
 private static WorldCup instance;
 public static WorldCup getInstance(){
  if(instance == null) //A
   instance = new WorldCup(); //B
  return instance;
 }
}

You may find something wrong here.What if you try to use SomeClass in a multithreaded application? Then a race condition results: two threads(1&2) could simultaneously execute the test to see if resource is null and, as a result, initialize resource twice. When 1 run to step B, but don't over to new WorldCup(), then 2 run to step A, and detect that instance is null. Synchronization mechanism is now may help you:

public class WorldCup {
 private static WorldCup instance;

 public static WorldCup getInstance() {
  synchronized (WorldCup.class) {
   if (instance == null) // A
    instance = new WorldCup();// B
   return instance;
  }
 }
}

Unfortunately, synchronized methods run much slower -- as much as
100 times than ordinary unsynchronized methods as switching between lock and unlock. But singleton pattern doesnot need to detect every time, we can do a lazy job.This is the DCL.

public class WorldCup {
 private static WorldCup instance;

public static WorldCup getInstance() {
  if (instance == null) { //C
   synchronized (WorldCup.class) {
    if (instance == null) // A
     instance = new WorldCup();// B
   }
  }
  return instance;
 }
}

Imangine that thread1 is inside the synchronized block,executing the statement instance = new WorldCup(); while thread2 is just entering getInstance(). Below is the memory effect:
Memory for the new WorldCup object will be allocated; the constructor for WorldCup will be called, initializing the member fields of the new object. Thread2 see these events in the following order: allocate memory, assign reference the instance ,call constructor. Suppose thread B comes along after he memory has been allocated and the instance field is set, but before the constructor is called. It sees that instance is not null, skips the synchronized block, and returns a reference to a partially constructed WorldCup! Needless to say, the result is neither expected nor desired.

----almost copy

posted on 2013-02-26 22:27  jnuyao  阅读(168)  评论(0编辑  收藏  举报