Thread Safe C# Singleton Pattern

142,634

Solution 1

Performing the lock is terribly expensive when compared to the simple pointer check instance != null.

The pattern you see here is called double-checked locking. Its purpose is to avoid the expensive lock operation which is only going to be needed once (when the singleton is first accessed). The implementation is such because it also has to ensure that when the singleton is initialized there will be no bugs resulting from thread race conditions.

Think of it this way: a bare null check (without a lock) is guaranteed to give you a correct usable answer only when that answer is "yes, the object is already constructed". But if the answer is "not constructed yet" then you don't have enough information because what you really wanted to know is that it's "not constructed yet and no other thread is intending to construct it shortly". So you use the outer check as a very quick initial test and you initiate the proper, bug-free but "expensive" procedure (lock then check) only if the answer is "no".

The above implementation is good enough for most cases, but at this point it's a good idea to go and read Jon Skeet's article on singletons in C# which also evaluates other alternatives.

Solution 2

The Lazy<T> version:

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy
        = new Lazy<Singleton>(() => new Singleton());

    public static Singleton Instance
        => lazy.Value;

    private Singleton() { }
}

Requires .NET 4 and C# 6.0 (VS2015) or newer.

Solution 3

Performing a lock: Quite cheap (still more expensive than a null test).

Performing a lock when another thread has it: You get the cost of whatever they've still to do while locking, added to your own time.

Performing a lock when another thread has it, and dozens of other threads are also waiting on it: Crippling.

For performance reasons, you always want to have locks that another thread wants, for the shortest period of time at all possible.

Of course it's easier to reason about "broad" locks than narrow, so it's worth starting with them broad and optimising as needed, but there are some cases that we learn from experience and familiarity where a narrower fits the pattern.

(Incidentally, if you can possibly just use private static volatile Singleton instance = new Singleton() or if you can possibly just not use singletons but use a static class instead, both are better in regards to these concerns).

Solution 4

The reason is performance. If instance != null (which will always be the case except the very first time), there is no need to do a costly lock: Two threads accessing the initialized singleton simultaneously would be synchronized unneccessarily.

Solution 5

In almost every case (that is: all cases except the very first ones), instance won't be null. Acquiring a lock is more costly than a simple check, so checking once the value of instance before locking is a nice and free optimization.

This pattern is called double-checked locking: http://en.wikipedia.org/wiki/Double-checked_locking

Share:
142,634
Wayne Phipps
Author by

Wayne Phipps

Updated on July 17, 2022

Comments

  • Wayne Phipps
    Wayne Phipps almost 2 years

    I have some questions regarding the the singleton pattern as documented here: http://msdn.microsoft.com/en-us/library/ff650316.aspx

    The following code is an extract from the article:

    using System;
    
    public sealed class Singleton
    {
       private static volatile Singleton instance;
       private static object syncRoot = new object();
    
       private Singleton() {}
    
       public static Singleton Instance
       {
          get 
          {
             if (instance == null) 
             {
                lock (syncRoot) 
                {
                   if (instance == null) 
                      instance = new Singleton();
                }
             }
    
             return instance;
          }
       }
    }
    

    Specifically, in the above example, is there a need to compare instance to null twice, before and after the lock? Is this necessary? Why not perform the lock first and make the comparison?

    Is there a problem in simplifying to the following?

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

    Is the performing the lock expensive?