In the past I've used a version of double check locking in order to implement efficient lazy creation of a singleton in .NET. This I've found to be the most performant implementation. However I've noticed recently that things are changing, when I run the code on a 64 bit CLR I see no difference between a type that has the before field init attribute present on or not. Both get initialised lazily in release mode and extremely quickly. The double check locking on 64 bit CLR is found to be less performant and therefore an unnecessary complication in the implementation.
In addition Ive recently installed .NET 3.5 SP1 and noticed now that there is a change in the 32 bit CLR for type initialisation. Whilst I still get the normal behaviour of before field init, the lazy CLR based initialisation is now extremely quick, almost the same as non lazy initialisation of the type. Again more importantly faster than my optimised double check locking implementation
My conclusion therefore is that moving forward, I'm comfortable in the fact that the very simple of singleton implementations is now acceptable even in cases where I'm aggressively requesting an instance of the singleton.
Below are two implementations of a singleton, the first using optimised locking the second using the CLR type initialisation to ensure lazy initialisation even in a multi threaded environment.
public class OptimisedLazyLogger
{
private static volatile OptimisedLazyLogger instance;
private static object creationLock = new object();
private OptimisedLazyLogger()
{
}
public static OptimisedLazyLogger GetInstance()
{
if (instance == null)
{
CreateInstance();
}
return instance;
}
private static void CreateInstance()
{
// only one thread at any one time
// can be inside this block
lock (creationLock)
{
if (instance == null)
{
instance = new OptimisedLazyLogger();
}
}
}
}
Implementation relying on CLR lazy initialisation
class LazyLogger
{
private static LazyLogger instance;
// Type constructor
static LazyLogger()
{
instance = new LazyLogger();
}
// ensure new can not be used outside the type
// to create an instance
private LazyLogger()
{
Console.WriteLine("Lazy Logger Created");
}
// Public method to allow clients to get to the single
// instance
public static LazyLogger GetInstance()
{
return instance;
}
public void LogMsg(string msg)
{
Console.WriteLine("Logger: {0}" , msg );
}
}