Singleton

One among the most popular pattern, the Singleton Pattern ensures a class could have just one instance, and provides a way to access it. Here you can see a preview of what is said on the matter in chapter five of Head First Design Patterns.

If the code you are dealing with is executed by just one thread, you could rely on a simple version of Singleton, that in Java looks something like that:
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

        return instance;
    }
}
Quite straightforward, but it could not work in a multithreading environment, since there is no synchronization on the code that actually create the resource. A simple patch would be this:
public static synchronized Singleton getInstance() {
    if(instance == null)
        instance = new Singleton();
    return instance;
}
The issue on this is that synchronization is expensive, and sometime we are not so happy to have to pay for it, when it is not strict necessity. We can move the creation of the instance in the static initializer, that is guaranteed by JVM to be thread safe:
public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {}

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

Cool, isn't it? The static initializer is called on the first attempt to access a Singleton method, and then what the getInstance() method has to do is just returning its instance.

Otherwise we could use the double-checked locking idiom, like showed here:
public class Singleton {
    private volatile static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if(instance == null) {
            synchronized(Singleton.class) {
                if(instance == null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}
The instance is volatile so each thead would ensure to check its actual value when using it. In getInstance() we enter a synchronized region only if we need it, so just if the instance is currently null. Once entered the critical region we have to check again the instance, to ensure it is still null.

No comments:

Post a Comment