Question

A recent question here had the following code (well, similar to this) to implement a singleton without synchronisation.

public class Singleton {
    private Singleton() {}
    private static class SingletonHolder { 
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

Now, I think understand what this is doing. Since the instance is static final, it's built long before any threads will call getInstance() so there's no real need for synchronisation.

Synchronisation would be needed only if two threads tried to call getInstance() at the same time (and that method did construction on first call rather than at "static final" time).

My question is therefore basically: why then would you ever prefer lazy construction of the singleton with something like:

public class Singleton {
    private Singleton() {}
    private static Singleton instance = null;
    public static synchronized Singleton getInstance() {
        if (instance == null)
            instance = new Singleton();
        return instance;
    }
}

My only thoughts were that using the static final method may introduce sequencing issue as in the C++ static initialisation order fiasco.

First off, does Java actually have this problem? I know order within a class is fully specified but does it somehow guarantee consistent order between classes (such as with a class loader)?

Secondly, if the order is consistent, why would the lazy construction option ever be advantageous?

Was it helpful?

Solution

Now, I think understand what this is doing. Since the instance is static final, it's built long before any threads will call getInstance() so there's no real need for synchronisation.

Not quite. It is built when the SingletonHolder class is initialized which happens the first time getInstance is called. The classloader has a separate locking mechanism, but after a class is loaded, no further locking is needed so this scheme does just enough locking to prevent multiple instantiation.

First off, does Java actually have this problem? I know order within a class is fully specified but does it somehow guarantee consistent order between classes (such as with a class loader)?

Java does have a problem where a class initialization cycle can lead to some class observing another class's static finals before they are initialized (technically before all static initializer blocks have run).

Consider

class A {
  static final int X = B.Y;
  // Call to Math.min defeats constant inlining
  static final int Y = Math.min(42, 43);
}

class B {
  static final int X = A.Y;
  static final int Y = Math.min(42, 43);
}

public class C {
  public static void main(String[] argv) {
    System.err.println("A.X=" + A.X + ", A.Y=" + A.Y);
    System.err.println("B.X=" + B.X + ", B.Y=" + B.Y);
  }
}

Running C prints

A.X=42, A.Y=42
B.X=0, B.Y=42

But in the idiom you posted, there is no cycle between the helper and the singleton so there is no reason to prefer lazy initialization.

OTHER TIPS

Now, I think understand what this is doing. Since the instance is static final, it's built long before any threads will call getInstance() so there's no real need for synchronisation.

No. SingletonHolder class will be loaded only when you invoke SingletonHolder.INSTANCE for the very first time. final Object will become visible to other threads only after it is fully constructed. Such lazy initialization is called Initialization on demand holder idiom.

In Effective Java, Joshua Bloch notes that "This idiom … exploits the guarantee that a class will not be initialized until it is used [JLS, 12.4.1]."

The patern that you described works for two reasons

  1. Class is loaded and initialized when first accessed (via SingletonHolder.INSTANCE here)
  2. Class loading and initialization is atomic in Java

So you do perform lazy initialization in a thread safe and efficient way. This pattern is better alternative to double lock (not working) solution to synchronized lazy init.

You initialize eagerly because you don't have to write a synchronized block or method. This is mainly because synchronization is generally considered expensive

Just a little note about the first implementation: the interesting thing here is that class initialization is used to replace classical synchronization.

Class initialization is very well defined in that no code can ever get access to anything of the class unless it is fully initialized (i.e. all static initializer code has run). And since an already loaded class can be accessed with about zero overhead, this restricts the "synchronization" overhead to those cases where there is an actual check to be done (i.e. "is the class loaded/initialized yet?").

One drawback of using the class loading mechanism is that it can be hard to debug when it breaks. If, for some reason, the Singleton constructor throws an exception, then the first caller to getInstance() will get that exception (wrapped in another one).

The second caller however will never see the root cause of the problem (he will simply get a NoClassDefFoundError). So if the first caller somehow ignores the problem, then you'll never be able to find out what exactly went wrong.

If you use simply synchronization, then the second called will just try to instantiate the Singleton again and will probably run into the same problem (or even succeed!).

A class is initialized when it's accessed at runtime. So init order is pretty much the execution order.

"Access" here refers to limited actions specified in the spec. The next section talks about initialization.

What's going on in your first example is equivalently

public static Singleton getSingleton()
{
    synchronized( SingletonHolder.class )
    {
        if( ! inited (SingletonHolder.class) )
            init( SingletonHolder.class );
    } 
    return SingletonHolder.INSTANCE;
}

( Once initialized, the sync block becomes useless; JVM will optimize it off. )

Semantically, this is not different from the 2nd impl. This doesn't really outshine "double checked locking", because it is double checked locking.

Since it piggybacks on class init semantics, it only works for static instances. In general, lazy evaluation is not limited to static instances; imagine there's an instance per session.

First off, does Java actually have this problem? I know order within a class is fully specified but does it somehow guarantee consistent order between classes (such as with a class loader)?

It does, but to a lesser degree than in C++:

  • If there is no dependency cycle, the static initialization occurs in the right order.

  • If there is a dependency cycle in the static initialization of a group of classes, then the order of initialization of the classes is indeterminate.

  • However, Java guarantees that default initialization of static fields (to null / zero / false) happens before any code gets to see the values of the fields. So a class can (in theory) be written to do the right thing irrespective of the initialization order.

Secondly, if the order is consistent, why would the lazy construction option ever be advantageous?

Lazy initialization is useful in a number of situations:

  • When the initialization has side effects that you don't want to happen unless the object is actually going to be used.

  • When the initialization is expensive, and you don't want it to waste time doing it unnecessarily ... or you want more important things to happen sooner (e.g. displaying the UI).

  • When the initialization depends on some state that is not available at static initialization time. (Though you need to be careful with this, because the state might not be available when lazy initialization gets triggered either.)

You can also implement lazy initialization using a synchronized getInstance() method. It is easier to understand, though it makes the getInstance() fractionally slower.

The code in the first version is the correct and best way to safely lazily construct a singleton. The Java Memory Model guarantees that INSTANCE will:

  • Only be initialized when first actually used (ie lazy), because classes are loaded only when first used
  • Be constructed exactly once so it's completely thread-safe, because all static initialization is guaranteed to be completed before the class is available for use

Version 1 is an excellent pattern to follow.

EDITED
Version 2 is thread safe, but a little bit expensive and more importantly, severely limits concurrency/throughput

I'm not into your code snippet, but I have an answer for your question. Yes, Java has an initialization order fiasco. I came across it with mutually dependent enums. An example would look like:

enum A {
  A1(B.B1);
  private final B b;
  A(B b) { this.b = b; }
  B getB() { return b; }
}

enum B {
  B1(A.A1);
  private final A a;
  B(A a) { this.a = a; }
  A getA() { return a; }
}

The key is that B.B1 must exist when creating instance A.A1. And to create A.A1 B.B1 must exist.

My real-life use case was bit more complicated - the relationship between the enums was in fact parent-child so one enum was returning reference to its parent, but the second array of its children. The children were private static fields of the enum. The interesting thing is that while developing on Windows everything was working fine, but in production—which is Solaris—the members of the child array were null. The array had the proper size but its elements were null because they were not available when the array was instantiated.

So I ended up with the synchronized initialization on the first call. :-)

The only correct singletone in Java can be declared not by class, but by enum:

public enum Singleton{
   INST;
   ... all other stuff from the class, including the private constructor
}

The use is as:

Singleton reference1ToSingleton=Singleton.INST;    

All other ways do not exclude repeated instantiation through reflection or if the source of class is directly present in the app source. Enum excludes everything. ( The final clone method in Enum ensures that enum constants can never be cloned )

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top