Friday, November 25, 2011

The Singleton Pattern

The Singleton Pattern is a way of making sure that only one instance of a class gets instantiated. It also sets up a global access point for the object.
Having a class that we can only have one instance of can be useful if, say, our class held a sort of global library of data. The Singleton would make sure there'd never be any confusion over the values of our data, ie. they never come up with two conflicting values, and we would also have a way of retrieving things from our global pool of data from anywhere.
The UML diagram looks very trivial for this pattern because of how simple it is. However, it does have its subtleties. Let's take a look.


The class contains an instance of itself (the one and only one instance) and a method for retrieving that instance.
Let's take a closer look

public class Singleton
{
    static Singleton _uniqueInstance;
    
    Singleton() { }

    public static Singleton GetInstance()
    {
        if (_uniqueInstance == null)
        {
            _uniqueInstance = new Singleton();
        }
        return _uniqueInstance;
    }
}
Perhaps you've noticed the private constructor. This is the key to the pattern. With a private constructor, we can only call new Singleton() from within the Singleton class itself. This allows us to have the class carefully monitor how it's instantiated through the public static method Singleton.GetInstance(), our global access point to the unique instance.
The first time we call Singleton.GetInstance(), the method checks to see if _uniqueInstance is null and since it is, it assigns a new Singleton() to _uniqueInstance and returns it.
The next time we call Singleton.GetInstance() (and every time afterwards), the check for null, returns false and the method returns the one and only one instance.

There is a problem with this set up as is though and maybe you've already noticed it. It isn't thread safe. If two threads were both accessing Singleton.GetInstance(), we could run into problems. Let's walk through a possible method call to see why.

Thread 1:
if (_uniqueInstance == null) //Thread 1 evaluates this to true

Thread 2 gets a turn:
if (_uniqueInstance == null) //Thread 2 also evaluates this to true

Thread 1:
_uniqueInstance = new Singleton(); //Thread 1 creates a new object.
return _uniqueInstance;

Thread 2's turn once again
_uniqueInstance = new Singleton(); //Thread 2 calls the constructor again.
return _uniqueInstance;
Oh no! Since Thread 2 had already evaluated true for the null check, it calls the constructor again and we get a second instance of _uniqueObject completely breaking everything!
Luckily, there's a way around this using the lock keyword.
lock essentially forces a thread to complete a section of code before another thread can get a turn.
Here's our new Singleton class:
public class Singleton
{
    static Singleton _uniqueInstance;
    static readonly object padLock = new object();

    Singleton() { }

    public static Singleton GetInstance()
    {
        lock(padLock)
        {
            if (_uniqueInstance == null)
            {
                _uniqueInstance = new Singleton();
            }
            return _uniqueInstance;
        }
    }
}

That's it! A simple but powerful way to make sure an object only ever has one instance.

Thanks for reading!

No comments :

Post a Comment