Alternative to Double-Checked Locking: Lazy<T>

A common pattern for lazy-initialization of a possibly-expensive type is double-checked locking.

The pattern is essentially this:

// member field
private volatile MyType myObject = null;
private object myLock = new object();

public MyType MyObject
{
    get
    {
        if (myObject == null)
        {
            lock(myLock)
            {
                if (myObject == null)
                {
                    myObject = new MyType();
                }
            }
        }
    }   
}

It’s quite common, and it’s also common to get it subtly wrong (not using volatile, for example).

However, in .Net 4, there’s a simpler way to do this: use Lazy<T>. This type uses a delegate to initialize the value with double-checked locking (there are other possible thread safety modes as well).

private Lazy<MyType> myObject = new Lazy<MyType>( () => new MyType );

public MyType MyObject
{
    get
    {
        return myObject.Value;
    }   
}

With Lazy<T>, the delegate you pass in will not be called until the Value property is accessed. Depending on the options you set, only a single thread will call your delegate and create the real type. I’d much rather do this than have to look at double-checked locking patterns scattered throughout a code base.

Like this tip? Check out my book, C # 4.0 How-To, where you’ll finds hundreds of great tips like this one.

3 thoughts on “Alternative to Double-Checked Locking: Lazy<T>

  1. Mike Ward

    Even more simple. Just use a static member. C# guarantees it will only be initialized once (yes, it’s thread safe) the first time the class is instantiated.

  2. Ben Stabile

    Mike W.,
    I don’t think the problem is about how to AVOID double-locking. The problem is how to ACHIEVE lazy loading of objects that are non-trivial to construct (i.e. those that may need to initialize state). Depending on what optimizations the compiler would otherwise put into effect, it might be possible for another thread to use it before it is fully initialized.

    Obviously, using Lazy clearly indicates our intention and allows us to get the result we want without double-locking and without worrying about how volatile variables are treated by current or future compilers on various platforms (which may have different memory architectures).

    Personally I think that if a variable requires these semantics then we should be using the AbstractFactory pattern with a proxy that encapsulates the lazy loading if necessary. We are talking here about “creational” patterns, and that complexity should be abstracted OUT of our core business objects and services. Why should our property getters be any more complicated (semantically) than:

    _factory.GetInstance();

Comments are closed.