Friday, January 11, 2013

"Singleton" Design Pattern in Java

Introduction

Singleton design pattern is a very disputable issue. There are tons of discussions in the Internet about Singleton usage in application design, why to use it, why not to use it, why singletons are evil, etc. In this post I want to put aside the “why?” part of the issue and concentrate on the “how?” part. In particular how to implement Singleton design pattern in Java. The rest of the post enumerates all Singleton implementation options I’ve ever encountered and describes their pros and cons. It doesn’t pretend for completeness but rather reflects my personal experience of working with this design pattern.

General Information

Singleton design pattern is intended to restrict the instantiation of a class to one (single) object. It should do the following things:

  • Ensure that only one instance of a class is created.
  • Provide a global point of access to that instance.

Let’s see how aforementioned points can be implemented in Java.

Singleton in Java

The following subsections describe different approaches to Singleton design pattern implementation in Java. If you are currently not interested in Singleton evolution in Java, want to skip all the background information and just need to find the best working solution quickly then jump straight to the last subsection which describes Singleton implementation using single-element enumeration.

First Option

The most obvious Singleton implementation looks like this:
public class Singleton1 {
    private static Singleton1 instance;

    private Singleton1() {
    }

    public static Singleton1 getInstance() {
        if (instance == null) {
            instance = new Singleton1();
        }

        return instance;
    }
}
This solution has one serious drawback: it doesn’t take threading into account and hence may not work as expected in multithreaded environment. If two or more threads call getInstance() method simultaneously then race condition occurs. For example, if 5 threads call getInstance() at the same time you may end up with static instance field being assigned up to 5 times (depending on the thread scheduling mechanism behavior).

Second Option

To tackle threading issue the previous option is suffering from you can try to use the following solution:
public class Singleton2 {
    private static final Singleton2 instance = new Singleton2();

    private Singleton2() {
    }

    public static Singleton2 getInstance() {
        return instance;
    }
}
In this implementation static instance field will be created during class initialization procedure. Java Language Specification guarantees this procedure to be thread-safe. Therefore this option is suitable for multithreaded environments, but it isn’t perfect either. It has the following drawbacks:

  • It cannot handle exceptions which may occur in the constructor.
  • Static instance field is no longer initialized lazily.

These points are not as critical as threading issue and they can be an acceptable trade-off depending on the task at hand. Moreover, you can easily overcome the first drawback by using a static initializer:
public class Singleton2 {
    private static final Singleton2 instance;

    static {
        try {
            instance = new Singleton2();
        } catch (Exception e) {
            // do possible error processing
            throw new RuntimeException(e);
        }
    }

    private Singleton2() throws Exception {
        // complex initialization logic which can throw an exception
    }

    public static Singleton2 getInstance() {
        return instance;
    }
}
This code looks a bit awkward, but it works and can be used if exceptions thrown from a constructor are a concern. But what if we want to preserve lazy initialization? This naturally leads us to the third option.

Third Option

The following Singleton implementation was initially suggested by Bill Pugh. It is called “Initialization on Demand Holder”. The trick is to use private nested class to hold Singleton instance:
public class Singleton3 {
    private Singleton3() {
    }

    private static class SingletonHolder {
        public static final Singleton3 instance = new Singleton3();
    }

    public static Singleton3 getInstance() {
        return SingletonHolder.instance;
    }
}
This solution leverages lazy initialization. Static instance field is initialized no earlier than SingletonHolder class is loaded and initialized. SingletonHolder class in its turn is loaded and initialized no earlier than it is first referenced. Finally SingletonHolder class is first referenced no earlier than getInstance() method is called. And this is exactly what we need. This implementation like the previous one is also based on the class initialization procedure which is guaranteed by Java Language Specification to be thread-safe. Similarly to the second option, if exceptions thrown from a constructor are a concern you can use a static initializer:
public class Singleton3 {
    private Singleton3() throws Exception {
        // complex initialization logic which can throw an exception
    }

    private static class SingletonHolder {
        public static final Singleton3 instance;

        static {
            try {
                instance = new Singleton3();
            } catch (Exception e) {
                // do possible error processing
                throw new RuntimeException(e);
            }
        }
    }

    public static Singleton3 getInstance() {
        return SingletonHolder.instance;
    }
}
So now we have a thread-safe Singleton implementation which initializes its instance lazily on demand. If you are using Java 1.4 or earlier then this is the approach to stick with.

Fourth Option

Before Bill Pugh suggested his “Initialization on Demand Holder” technique one of the most popular implementations of lazy-initializing thread-safe Singleton used to look like this:
public class Singleton4 {
    private static Singleton4 instance;

    private Singleton4() {
    }

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

        return instance;
    }
}
This solution has only one drawback: it uses synchronization inefficiently. Synchronization is necessary only until the static instance field is not initialized. After that it simply wastes CPU cycles. In earlier implementations of the Java Platform synchronized methods and blocks were quite costly. That’s why the fifth option emerged.

Fifth Option

This solution is intended to tackle inefficient synchronization usage of the previous option. It leverages Double-Checked Locking pattern and like the previous one it also used to be very popular:
public class Singleton5 {
    private static Singleton5 instance;

    private Singleton5() {
    }

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

        return instance;
    }
}
There is only one problem with this approach: it doesn’t work! Broken Double-Checked Locking pattern is a complicated topic which goes beyond the scope of this post, but the interested reader can find more information here.

Sixth Option

Bill Pugh’s efforts on Double-Checked Locking led to changes in Java Memory Model which were incorporated in the Java Platform starting from Java 5. With these changes it became possible to make the previous solution work by adding volatile modifier to the instance field declaration:
public class Singleton6 {
    private static volatile Singleton6 instance;

    private Singleton6() {
    }

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

        return instance;
    }
}
This solution will work correctly in Java 5 and above.

Seventh Option

All previously mentioned Singleton implementations suffer from the following drawbacks:

  • It is possible to instantiate more than one Singleton instance using Java reflections. All you need to do is to get the corresponding Constructor instance, make it accessible using method setAccessible() and call the constructor reflectively. You can protect your Singleton class against this invocation by throwing an exception from the constructor if an attempt to create more than one Singleton instance is taken.
  • If Singleton class implements Serializable interface additional precautions should be taken to maintain Singleton guarantee: all fields of the Singleton class should be made transient and readResolve() method should be implemented to replace any deserialized instances coming from ObjectInputStream with the only true one.

While you do can bother with tackling the aforementioned problems manually, there is a much better approach which solves them automatically:
public enum Singleton7 {
    INSTANCE
    // ...
}
As you might know, enumerations in Java are not just a set of constants. They can contain method implementations and hence can be used to implement Singleton’s logic instead of plain class. Moreover, all serialization and multiple instantiation issues are handled automatically. I first encountered the idea of using single-element enumerations to implement Singleton design pattern in Joshua Bloch’s Effective Java book. At the time of this writing it is the best way to implement Singleton in Java.

Thanks for reading,
See you soon!

No comments:

Post a Comment