pátek 19. června 2009

Java: Standalone Pattern and Lazy Initialization with Concurrent Access

Whats wrong with this piece of code?
public class MyClass {
  private static MyClass instance = null;
  public static MyClass getInstance() {
    if (instance == null) instance = new MyClass();
    return instance;
  }
}

Nothing, if you have single thread application only. Otherwise add a magic word synchronized:
public class MyClass {
  private static MyClass instance = null;
  public static synchronized MyClass getInstance() {
    if (instance == null) instance = new MyClass();
    return instance;
  }
}

Now, it's more safe, but a little bit slower. I was thinking about speeding it up by double check locking:
public class MyClass {
  private static MyClass instance = null;
  public static MyClass getInstance() {
    if (instance != null) return instance;
    synchronized (MyClass.class) {
      // yes, one more check in synchronized block
      if (instance == null) instance = new MyClass();
    }
    return instance;
  }
}

Danger! There's hidden snag in this code. Fortunately, I have stumbled upon the See Bill Pugh's page http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html explaining what's wrong with this piece of the code. Briefly, the construction of the object instance = new MyClass() is not an atomic operation. So a thread can get the instance variable while some other thread is still processing the constructor of the same instance object. You can find some old web pages advising to use double check locking in a wrong way, e.g. http://www.javaworld.com/javaworld/javatips/jw-javatip67.html. Bill Pugh's research has changed the memory model in Java 1.5, so there is a new keyword volatile which solves the hidden snag:
public class MyClass {
  private static volatile MyClass instance = null;
  public static MyClass getInstance() {
    if (instance != null) return instance;
    synchronized (MyClass.class) {
      // yes, one more check in synchronized block
      if (instance == null) instance = new MyClass();
    }
    return instance;
  }
}

Java has some nice semantic and syntactic sugar for multi-threaded programming. But this simple example shows, that one should not venture into the Java multi-threaded programming without deeper study of the Java internals and common concurrent programming principles.

Žádné komentáře: