Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different ways to write singleton in Java

Tags:

java

singleton

The classic of writing a singleton in java is like this:

public class SingletonObject
{
    private SingletonObject()
    {
    }

    public static SingletonObject getSingletonObject()
    {
      if (ref == null)
          // it's ok, we can call this constructor
          ref = new SingletonObject();
      return ref;
    }

    private static SingletonObject ref;
}

and we can add synchronized keyword if we need it to run in multithreaded cases.

But I prefer to write it as:

public class SingletonObject
{
    private SingletonObject()
    {
        // no code req'd
    }

    public static SingletonObject getSingletonObject()
    {
      return ref;
    }

    private static SingletonObject ref = new SingletonObject();
}

which I think is more concise, but strangely I didn't see any sample code written in this way, is there any bad effects if I wrote my code in this way?

like image 626
gleery Avatar asked Dec 10 '09 07:12

gleery


People also ask

How do you declare a singleton in Java?

In Java, Singleton is a design pattern that ensures that a class can only have one object. To create a singleton class, a class must implement the following properties: Create a private constructor of the class to restrict object creation outside of the class.

What is the best way to implement Singleton in Java?

The most popular approach is to implement a Singleton by creating a regular class and making sure it has: A private constructor. A static field containing its only instance. A static factory method for obtaining the instance.

What are the different ways we can break a Singleton pattern in Java?

Serialization is used to convert an object of byte stream and save in a file or send over a network. Suppose you serialize an object of a singleton class. Then if you de-serialize that object it will create a new instance and hence break the singleton pattern.


3 Answers

Well, in the latter case the singleton object gets created before it is ever needed, but in most cases that's probably not horribly bad.

By the way, Joshua Bloch recommends (in Effective Java, 2nd ed, item 3) implementing singletons using a single-element enum:

public enum SingletonObject { 
    INSTANCE;
}

He gives the following justification:

[...] it is more concise, provides serialization machinery for free, and provides an ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection attacks. While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton.

like image 125
Jonik Avatar answered Nov 15 '22 22:11

Jonik


The difference between your code and the "sample code" is that your singleton is instantiated when the class is loaded, while in the "sample" version, it is not instantiated until it is actually needed.

like image 26
Anon. Avatar answered Nov 15 '22 21:11

Anon.


In the second form, your singleton is eagerly loaded and this is actually the preferred form (and the first one isn't thread-safe as you mentioned it yourself). Eager loading is not a bad thing for production code but there are contexts where you might want to lazy load your singletons, as discussed by the author of Guice, Bob Lee, in Lazy Loading Singletons that I'm quoting below:

First, why would you want to lazy load a singleton? In production, you typically want to eagerly load all your singletons so you catch errors early and take any performance hit up front, but in tests and during development, you only want to load what you absolutely need so as not to waste time.

Before Java 1.5, I lazy loaded singletons using plain old synchronization, simple but effective:

static Singleton instance;

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

Changes to the memory model in 1.5 enabled the infamous Double-Checked Locking (DCL) idiom. To implement DCL, you check a volatile field in the common path and only synchronize when necessary:

static volatile Singleton instance;

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

But volatile isn't that much faster than synchronized, synchronized is pretty fast nowadays, and DCL requires more code, so even after 1.5 came out, I continued using plain old synchronization.

Imagine my surprise today when Jeremy Manson pointed me to the Initialization on Demand Holder (IODH) idiom which requires very little code and has zero synchronization overhead. Zero, as in even faster than volatile. IODH requires the same number of lines of code as plain old synchronization, and it's faster than DCL!

IODH utilizes lazy class initialization. The JVM won't execute a class's static initializer until you actually touch something in the class. This applies to static nested classes, too. In the following example, the JLS guarantees the JVM will not initialize instance until someone calls getInstance():

static class SingletonHolder {
  static Singleton instance = new Singleton();    
}

public static Singleton getInstance() {
  return SingletonHolder.instance;
}

[...]

Update: Credit where credit is due, Effective Java (copyright 2001) detailed this pattern under item 48. It goes on to point out that you still have to use synchronization or DCL in non-static contexts.

I also switched singleton handling in my framework from synchronization to DCL and saw another 10% performance boost (compared to before I started using cglib's fast reflection). I only used one thread in my micro-benchmark, so the boost to concurrency could be even greater given that I replaced a heavily contended lock with a relatively fine grained volatile field access.

Note that Joshua Bloch now recommends (since Effective Java, 2nd ed) to implement singletons using a single-element enum as pointed out by Jonik.

like image 43
Pascal Thivent Avatar answered Nov 15 '22 23:11

Pascal Thivent