Thread Safe C# Singleton Pattern

Wayne Phipps picture Wayne Phipps · Sep 7, 2012 · Viewed 119.5k times · Source

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?

Answer

Jon picture Jon · Sep 7, 2012

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.