共用方式為


Singleton

The Singleton design pattern is seemingly one of the most simple patterns out there, yet on several channels (forums, discussion lists etc.) people seem to be asking what the best way to do it is.

A quick search for singleton implementations yields some very useful results, and given the simplicity of the pattern the language should not be a barrier for anyone. Some of the implementations out there are truly naive, and it shows something extremely common: even the simplest piece of code can have so much depth that people can easily make the wrong choice.

The simplest implementation is the following:

 public class Singleton
{
    private static Singleton instance;

    private Singleton() {}

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new Singleton();
            }

            return instance;
        }
    }
}

Is there something wrong with this? Well, the answer is no. If you write this on a college exam, you will most likely get all the points. The catch is that you can’t have multiple threads calling Singleton.Instance, or you risk having multiple Singletons out there, which kind of defeats the purpose of the whole pattern :)

While in general I’m a fan of keeping things as simple as possible, in today’s day and age where almost all computers have at least two cores, there’s really no excuse of designing things for just one thread. So let’s make this solution a thread-safe one:

 public class Singleton
{
    private static volatile Singleton instance;
    private static readonly object mutex = new object();

    private Singleton() {}

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock (mutex)
                {
                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                }
            }

            return instance;
        }
    }
}

For those who are scratching their head about the double-check, just think about what happens if two threads access the first check at the same time, and that should give you the answer ;)

Now this solution will always work, regardless if you have just one thread or thousands accessing Singleton.Instance. The only argument for this code is that it’s not as simple as the first option, and that’s very true. So let’s look at this third solution, which should address this concern while keeping everything we have so far: a multi-threaded Singleton implementation:

 public class Singleton
{
    private static readonly Singleton instance;

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

    private Singleton() {}

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }
}

This is a bit specific to .NET, but it works like this: a static constructor is guaranteed to be called only once per AppDomain, and only when it’s needed (a static member is called or an instance of that object is created). So we can safely get rid of our lock and the checks, and rely on the CLR doing the right thing. So we now have a thread-safe, relatively pretty implementation for the Singleton pattern. The only change we can do to this is add lazy loading, which may slightly improve performance if you have other static methods, but chances are that’s not going to be your bottleneck so don’t waste your time.

All-in-all, I think this is a great example of the power of how very subtle changes drastically change the look or behavior of a piece of software. It also forces people to think a lot more than they probably thought they would need to, which will hopefully make it habitual :)

-Cos

Comments

  • Anonymous
    September 09, 2009
    I generally find it best to completely avoid the singleton pattern. Here are just a few of the things that this naive implementation does not consider:Order of initialization of multiple singletons and other global stateDeposing and Finalization Order of cleanup of multiple singletons and other global state Thread safety of the methods on the actual singleton class itself Dependency injection for unit testing Lots more Also, this kind of singleton is only a singleton for a particular appdomain (as you point out). Multiple instances of the program are going to have their own singleton. If your singleton accesses the world outside of your app domain (like the file system), you still need to support multiple instances and handle this shared state. If there is only going to be one of these ever, it should exist in a server process and live inside a named global mutex which will enforce the singleton behavior, but you can't cram that into a static constructor or global property getter. Even then, I prefer to use such a global named mutex for user convience of preventing undesired multiple instances. I'd provide an option to disable that because sooner or later you're going to want to run two instances of a server process, maybe on two different ports or something.I see singletons as a kind of code smell. Every time I have created one, I have regretted it later. Now, whenever I feel the urge to create one, I ask myself why and always come up with a better solution.