Singleton

Content:

  1. Introduction
  2. What it is
  3. Implementation
    1. C++
    2. Java
    3. .NET
  4. The problems
    1. It is not needed
    2. It makes testing difficult
    3. It makes the application code hard to read
    4. It doesn't do what it claims to do
    5. Conclusion
  5. The crazy problem

Introduction:

Few patterns are as controversial as the singleton pattern.

It was widely used in the early 00's, but in recent years it has been widely considered deprecated. Especially among the junior developers wanting to have the "right" opinions.

The reality about pros and cons are a bit more complex. And this article will take a deeper dive into matters.

Disclaimer: I hope I have gotten everything regarding thread safety and memory models correct, but it is complicated stuff, so please forgive me if I have gotten something wrong.

What it is:

Singleton pattern come from the well known GoF book "Design Patterns" by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides.

The problem the pattern solves is to have a class where there can only exist one instance.

Implementation:

There are a couple of typical solutions:

The classic solution is:

class Singleton {
    static Singleton instance = null
    Singleton GetInstance() {
        if(instance == null) {
            instance = new Singleton()
        }
        return instance
    }
    ...
}

The simple solution is:

class Singleton {
    static Singleton instance = new Singleton()
    Singleton GetInstance() {
        return instance
    }
    ...
}

C++:

This is the original implementation from the GoF book.

OriginalSingleton.h:

#ifndef ORIGINAL_SINGLETON_H
#define ORIGINAL_SINGLETON_H

#include <iostream>

using namespace std;

class OriginalSingleton
{
private:
    static OriginalSingleton* instance;
    int SomeState;
    OriginalSingleton() { SomeState = 123; }
public:
    static OriginalSingleton* Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

OriginalSingleton.cpp:

#include <cstddef>

using namespace std;

#include "OriginalSingleton.h"

OriginalSingleton* OriginalSingleton::instance = NULL;

OriginalSingleton* OriginalSingleton::Instance()
{
    if(instance == NULL)
    {
        instance = new OriginalSingleton();
    }
    return instance;
}

Thread-safe: NO.

This is the original implementation with changes that actually prevents multiple instances by also preventing copying.

ClassicSingleton.h:

#ifndef CLASSIC_SINGLETON_H
#define CLASSIC_SINGLETON_H

#include <iostream>

using namespace std;

class ClassicSingleton
{
private:
    static ClassicSingleton* instance;
    int SomeState;
    ClassicSingleton() { SomeState = 123; }
    ClassicSingleton(const ClassicSingleton& original) { };
    ClassicSingleton& operator=(const ClassicSingleton& original) { return *this; };
public:
    static ClassicSingleton* Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

ClassicSingleton.cpp:

#include <cstddef>

using namespace std;

#include "ClassicSingleton.h"

ClassicSingleton* ClassicSingleton::instance = NULL;

ClassicSingleton* ClassicSingleton::Instance()
{
    if(instance == NULL)
    {
        instance = new ClassicSingleton();
    }
    return instance;
}

Thread-safe: NO.

This is the simple approach with static initialization

SimpleSingleton.h:

#ifndef SIMPLE_SINGLETON_H
#define SIMPLE_SINGLETON_H

#include <iostream>

using namespace std;

class SimpleSingleton
{
private:
    static SimpleSingleton* instance;
    int SomeState;
    SimpleSingleton() { SomeState = 123; }
    SimpleSingleton(const SimpleSingleton& original) { };
    SimpleSingleton& operator=(const SimpleSingleton& original) { return *this; };
public:
    static SimpleSingleton* Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

SimpleSingleton.cpp:

#include <cstddef>

using namespace std;

#include "SimpleSingleton.h"

SimpleSingleton* SimpleSingleton::instance = new SimpleSingleton();

SimpleSingleton* SimpleSingleton::Instance()
{
    return instance;
}

Thread-safe: YES since C++ 11.

This is the same implementation as "C++ classic" - it just utilize a few modern C++ constructs.

ClassicSingleton11.h:

#ifndef CLASSIC_SINGLETON_11_H
#define CLASSIC_SINGLETON_11_H

#include <iostream>

using namespace std;

class ClassicSingleton11
{
private:
    static ClassicSingleton11* instance;
    int SomeState;
    ClassicSingleton11() { SomeState = 123; }
public:
    ClassicSingleton11(const ClassicSingleton11& original) = delete;
    ClassicSingleton11& operator=(const ClassicSingleton11& original) = delete;
    static ClassicSingleton11& Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

ClassicSingleton11.cpp:

#include <cstddef>

using namespace std;

#include "ClassicSingleton11.h"

ClassicSingleton11* ClassicSingleton11::instance = nullptr;

ClassicSingleton11& ClassicSingleton11::Instance()
{
    if(instance == nullptr)
    {
        instance = new ClassicSingleton11();
    }
    return *instance;
}

Thread-safe: NO.

This is the same implementation as "C++ simple" - it just utilize a few modern C++ constructs.

SimpleSingleton11.h:

#ifndef SIMPLE_SINGLETON_11_H
#define SIMPLE_SINGLETON_11_H

#include <iostream>

using namespace std;

class SimpleSingleton11
{
private:
    static SimpleSingleton11* instance;
    int SomeState;
    SimpleSingleton11() { SomeState = 123; }
public:
    SimpleSingleton11(const SimpleSingleton11& original) = delete;
    SimpleSingleton11& operator=(const SimpleSingleton11& original) = delete;
    static SimpleSingleton11& Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

SimpleSingleton11.cpp:

#include <cstddef>

using namespace std;

#include "SimpleSingleton11.h"

SimpleSingleton11* SimpleSingleton11::instance = new SimpleSingleton11();

SimpleSingleton11& SimpleSingleton11::Instance()
{
    return *instance;
}

Thread-safe: YES since C++ 11.

This implementation is called Meyers singleton because it come from the wellknown book "Effective C++" by Scott Meyers.

MeyersSingleton11.h:

#ifndef MEYERS_SINGLETON_11_H
#define MEYERS_SINGLETON_11_H

#include <iostream>

using namespace std;

class MeyersSingleton11
{
private:
    int SomeState;
    MeyersSingleton11() { SomeState = 123; }
public:
    MeyersSingleton11(const MeyersSingleton11& original) = delete;
    MeyersSingleton11& operator=(const MeyersSingleton11& original) = delete;
    static MeyersSingleton11& Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

MeyersSingleton11.cpp:

#include "MeyersSingleton11.h"

MeyersSingleton11& MeyersSingleton11::Instance()
{
    static MeyersSingleton11 instance;
    return instance;
}

Thread-safe: YES since C++ 11.

Which one to pick?

I will recommend the modern C++ simple singleton or the Meyers singleton. They are both readable, thread safe and close to the original concept. They are in fact very similar. Meyers singleton just do something smart with the scope.

Java:

This is an implementation similar to GoF.

ClassicSingleton.java:

package singleton;

public class ClassicSingleton {
    private static ClassicSingleton instance = null;
    private int someState;
    private ClassicSingleton() {
        someState = 123;
    }
    public static ClassicSingleton getInstance() {
        if(instance == null) {
            instance = new ClassicSingleton();
        }
        return instance;
    }
    public void someMethod() {
        System.out.println(someState);
    }
}

Thread-safe: NO.

This is the simple approach with static initialization.

SimpleSingleton.java:

package singleton;

public class SimpleSingleton {
    private static final SimpleSingleton instance = new SimpleSingleton();
    private int someState;
    private SimpleSingleton() {
        someState = 123;
    }
    public static SimpleSingleton getInstance() {
        return instance;
    }
    public void someMethod() {
        System.out.println(someState);
    }
}

Thread-safe: YES.

The enum singleton come from the wellknown book "Effective Java" by Joshua Bloch.

EnumSingleton.java:

package singleton;

public enum EnumSingleton {
    INSTANCE;
    private int someState;
    private EnumSingleton() {
        someState = 123;
    }
    public void someMethod() {
        System.out.println(someState);
    }
}

Thread-safe: YES.

I will recommend the simple singleton - not the enum singleton. The enum singleton is the technical most elegant design, but this type of usage of enum is not what enum is intended for. If you ask 1000 Java developers about this code, then 10 will understand why it works, 90 will have heard about it (Joshua Bloch is a guru in the Java development world), 400 will google it to understand it and 500 will be confused. Confusing 50% is bad, so no enum singleton. And it does not matter if the confused percentage is just 25% or even 10%.

.NET:

This is an implementation similar to GoF.

ClassicSingleton.cs:

using System;

namespace Singleton
{
    public class ClassicSingleton
    {
        private static ClassicSingleton instance;
        private int someState;
        private ClassicSingleton() 
        {
            someState = 123;
        }
        public static ClassicSingleton Instance
        {
            get
            {
                if(instance == null)
                {
                    instance = new ClassicSingleton();
                }
                return instance;
            }
        }
        public void SomeMethod()
        {
            Console.WriteLine(someState);
        }
    }
}

Thread-safe: NO.

This is an implementation similar to GoF.

ClassicSingleton.vb:

Imports System

Namespace Singleton
    Public Class ClassicSingleton
        Private Shared m_instance As ClassicSingleton
        Private someState As Integer
        Private Sub New()
            someState = 123
        End Sub
        Public Shared ReadOnly Property Instance() As ClassicSingleton
            Get
                If m_instance Is Nothing Then
                    m_instance = New ClassicSingleton()
                End If
                Return m_instance
            End Get
        End Property
        Public Sub SomeMethod()
            Console.WriteLine(someState)
        End Sub
    End Class
End Namespace

Thread-safe: NO.

This is the simple approach with static initialization.

SimpleSingleton.cs:

using System;

namespace Singleton
{
    public class SimpleSingleton
    {
        private static readonly SimpleSingleton instance = new SimpleSingleton();
        private int someState;
        private SimpleSingleton() 
        {
            someState = 123;
        }
        public static SimpleSingleton Instance
        {
            get
            {
                return instance;
            }
        }
        public void SomeMethod()
        {
            Console.WriteLine(someState);
        }
    }
}

Thread-safe: YES.

This is the simple approach with static initialization.

SimpleSingleton.vb:

Imports System

Namespace Singleton
    Public Class SimpleSingleton
        Private Shared ReadOnly m_instance As New SimpleSingleton()
        Private someState As Integer
        Private Sub New()
            someState = 123
        End Sub
        Public Shared ReadOnly Property Instance() As SimpleSingleton
            Get
                Return m_instance
            End Get
        End Property
        Public Sub SomeMethod()
            Console.WriteLine(someState)
        End Sub
    End Class
End Namespace

Thread-safe: YES.

I will recommend the simple singleton.

The problems:

The singleton pattern has been criticized for several reasons:

But let us take a look at each of the reasons.

It is not needed:

The argument is that enforcing only once instance of a class is an artifical problem not happening in real life.

But reality is that it is a common requirement.

so it is obvious that there are an actual need.

This argument against singleton is not valid.

Typical usage scenarios include:

It makes testing difficult:

The argument is that a singleton cannot be mocked and that makes unit testing of code using the singleton difficult/impossible.

It is true that a singleton can not be mocked.

But an object created with new can not be mocked either. Only objects created via DI can be switched to a mock using configuration.

And it is still possible to replace a singleton implementation with a mock by using a different deployment artifact.

This argument against singleton has very limited validity.

It makes the application code hard to read:

The argument is that a singleton is just a bad old fashioned global variable in disguise and that it makes the code very hard to read, because any code anywhere can access the singleton.

That is true.

And it means that:

  1. singletons should only be used if it has significant benefits that outweigh the problem
  2. singletons should be designed for that:

This argument is valid and require both justification and mitigation.

It doesn't do what it claims to do:

The argument is that it is actually possible to have multiple instances of a singleton.

The most relevant case is a cluster with the application running on multiple nodes. In that case each node will have an instance of the singleton.

Trivial/obvious, but still something that need to be handled in the design.

Singleton is only good in this case if one of:

This argument is somewhat valid and must be considered.

Another case is that in a JVM then it is actually possible to create multiple instances of a singleton using multiple classloaders - a singleton is only a singleton within a single classloader. Similar with .NET Framework and application domains. But this is rarely a problem since multiple classloader/appdomains usually means that separation is desired.

It is also possible to create multiple instances of a singleton using reflection or dynamic code modification. But this is probably not relevant - the purpose of singleton is to prevent accidental multiple instances - not to prevent malicious multiple instances.

Conclusion:

Do not discard the possibility of using singleton pattern, but do carefully evaluate its fit and usage before chosing it.

It is a valuable tool in the developers toolbox, but a tool that should probably not be used frequently.

The crazy problem:

An obscure problem within singleton pattern has gotten a lot of attention among some of the worlds best software engineers.

The problem is how to design a singleton that is first initialized when the instance is retrieved the first time and is still thread safe.

The alledged purpose should be to avoid costly initialization if not needed.

I think the problem is totally bullshit.

FIRST. Both Java and .NET by default does lazy initialization of static fields. One need to do something special to force early initialization. And C++ has the Meyers singleton that also does lazy initialization. So the problem does rarely occur in the real world.

In Java early initialization of a static field will happen if one of:

Neither makes much sense for a singleton.

Same in .NET - either calling another static method or calling the obscure RuntimeHelpers.RunClassConstructor on the class.

SECOND. Most singletons in the real world has simple fast constructors. So the problem rarely matters in the real world.

THIRD. The trivial solutions are almost always good enough in the real world.

So it is a problem that rarely occur, rarely matters and where the trivial solutions are good enough in the real world.

So a bullshit problem.

But because the problem rise some interesting questions related to multi-threading and memory models, then a lot of very smart people has spent a lot of time on this problem.

Som of the classic texts are:

  1. Double-checked locking and the Singleton pattern / Peter Haggar
  2. The "Double-Checked Locking is Broken" Declaration / David Bacon, Joshua Bloch, Jeff Bogda, Cliff Click, Paul Haahr, Doug Lea, Tom May, Jan-Willem Maessen, Jeremy Manson, John Mitchell Kelvin Nilsen, Bill Pugh, Emin Gun Sirer
  3. volatile and MemoryBarrier()... / Brad Adams
  4. Memory Models - Understand the Impact of Low-Lock Techniques in Multithreaded Apps / Vance Morrison
  5. C# in Depth - Implementing the Singleton Pattern in C# / Jon Skeet
  6. C++ and the Perils of Double-Checked Locking / Scott Meyers, Andrei Alexandrescu
  7. Double-Checked Locking is Fixed In C++11

Synchronized solution:

The classic singleton first initalize when the get instance method is called. Without anything special, then it is not thread safe as two threads calling the get instance method could both create instances.

An easy fix is to ensure that only one thread execute the critical code at a time.

class Singleton {
    static Singleton instance = null
    Singleton GetInstance() {
        only one thread at a time {
            if(instance == null) {
                instance = new Singleton()
            }
        }
        return instance
    }
    ...
}

SynchronizedSingleton.java:

package singleton;

public class SynchronizedSingleton {
    private static SynchronizedSingleton instance = null;
    private int someState;
    private SynchronizedSingleton() {
        someState = 123;
    }
    public static synchronized SynchronizedSingleton getInstance() {
        if(instance == null) {
            instance = new SynchronizedSingleton();
        }
        return instance;
    }
    public void someMethod() {
        System.out.println(someState);
    }
}

SynchronizedSingleton.cs:

using System;

namespace Singleton
{
    public class SynchronizedSingleton
    {
        private static SynchronizedSingleton instance;
        private static readonly object mylock = new object();
        private int someState;
        private SynchronizedSingleton() 
        {
            someState = 123;
        }
        public static SynchronizedSingleton Instance
        {
            get
            {
                lock(mylock)
                {
                    if(instance == null)
                    {
                        instance = new SynchronizedSingleton();
                    }
                }
                return instance;
            }
        }
        public void SomeMethod()
        {
            Console.WriteLine(someState);
        }
    }
}

SynchronizedSingleton.vb:

Imports System

Namespace Singleton
    Public Class SynchronizedSingleton
        Private Shared m_instance As SynchronizedSingleton
        Private Shared ReadOnly mylock As New Object()
        Private someState As Integer
        Private Sub New()
            someState = 123
        End Sub
        Public Shared ReadOnly Property Instance() As SynchronizedSingleton
            Get
                SyncLock mylock
                    If m_instance Is Nothing Then
                        m_instance = New SynchronizedSingleton()
                    End If
                End SyncLock
                Return m_instance
            End Get
        End Property
        Public Sub SomeMethod()
            Console.WriteLine(someState)
        End Sub
    End Class
End Namespace

SynchronizedSingleton.h:

#ifndef SYNCHRONIZED_SINGLETON_H
#define SYNCHRONIZED_SINGLETON_H

#include <iostream>

using namespace std;

class SynchronizedSingleton
{
private:
    static SynchronizedSingleton* instance;
    int SomeState;
    SynchronizedSingleton() { SomeState = 123; }
    SynchronizedSingleton(const SynchronizedSingleton& original) { };
    SynchronizedSingleton& operator=(const SynchronizedSingleton& original) { return *this; };
public:
    static SynchronizedSingleton* Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

SynchronizedSingleton.cpp:

#include <cstddef>

using namespace std;

#include "Lock.h"

#include "SynchronizedSingleton.h"

SynchronizedSingleton* SynchronizedSingleton::instance = NULL;

SynchronizedSingleton* SynchronizedSingleton::Instance()
{
    Lock mylock;
    if(instance == NULL)
    {
        instance = new SynchronizedSingleton();
    }
    return instance;
}

Lock.h:

#ifndef LOCK_H
#define LOCK_H

void lock_setup();
void lock_destroy();

class Lock
{
public:
    Lock();
    virtual ~Lock();
};

#endif

Lock.cpp:

#ifdef WIN32_THREADS
#include <windows.h>
static CRITICAL_SECTION cs;
#elif POSIX_THREADS
#include <pthread.h>
static pthread_mutex_t mtx;
#else
#error "No threading model specified"
#endif

#include "Lock.h"

void lock_setup()
{
#ifdef WIN32_THREADS
    InitializeCriticalSection(&cs);        
#endif        
#ifdef POSIX_THREADS
    pthread_mutex_init(&mtx, NULL);
#endif
}

void lock_destroy()
{
#ifdef WIN32_THREADS
    DeleteCriticalSection(&cs);        
#endif        
#ifdef POSIX_THREADS
    pthread_mutex_destroy(&mtx);
#endif
}

Lock::Lock()
{
#ifdef WIN32_THREADS
    EnterCriticalSection(&cs);        
#endif        
#ifdef POSIX_THREADS
    pthread_mutex_lock(&mtx);
#endif
}

Lock::~Lock()
{
#ifdef WIN32_THREADS
    LeaveCriticalSection(&cs);        
#endif        
#ifdef POSIX_THREADS
    pthread_mutex_unlock(&mtx);
#endif
}

SynchronizedSingleton11.h:

#ifndef SYNCHRONIZED_SINGLETON_11_H
#define SYNCHRONIZED_SINGLETON_11_H

#include <iostream>

using namespace std;

class SynchronizedSingleton11
{
private:
    static SynchronizedSingleton11* instance;
    int SomeState;
    SynchronizedSingleton11() { SomeState = 123; }
public:
    SynchronizedSingleton11(const SynchronizedSingleton11& original) = delete;
    SynchronizedSingleton11& operator=(const SynchronizedSingleton11& original) = delete;
    static SynchronizedSingleton11& Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

SynchronizedSingleton11.cpp:

#include <cstddef>
#include <mutex>

using namespace std;

static mutex mymutex;

#include "SynchronizedSingleton11.h"

SynchronizedSingleton11* SynchronizedSingleton11::instance = nullptr;

SynchronizedSingleton11& SynchronizedSingleton11::Instance()
{
    lock_guard<mutex> mylock(mymutex);
    if(instance == nullptr)
    {
        instance = new SynchronizedSingleton11();
    }
    return *instance;
}

Double locking solution:

This solution was originally proposed to be faster than the synchronized solution and still thread safe by only by only synchronize if the instance field is null.

class Singleton {
    static Singleton instance = null
    Singleton GetInstance() {
        if(instance == null) {
            only one thread at a time {
                if(instance == null) {
                    instance = new Singleton()
                }
            }
        }
        return instance
    }
    ...
}

But it is not thread safe!

The explanation is that the code:

                    instance = new Singleton()

result in logical low level code like:

              temp_ptr = allocate memory for Singleton
              call Singleton constructor with temp_ptr
              instance = temp_ptr

If that logical low level code is what actually get executed physical, then everything is fine.

But if it end up being executed physical like:

              temp_ptr = allocate memory for Singleton
              instance = temp_ptr
              call Singleton constructor for temp_ptr

due to instruction reordering then another thread could see instance == null return false but instance pointing to an uninitialized object.

So double locking is only safe if both:

  1. the compiler is prohibited from reording like that
  2. the CPU is prohibited from reording like that

Supposedly MS C# compiler does not reorder and current x86-64 CPU's does not reorder due to its strong memory model (*).

*) It is common to categorize memory models like:

Very strong (no reordering)
x86
Strong (limited reordering only store-load)
x86-64, SPARC
Weak (reordering with consideration for dependencies)
ARM, Power, Itanium
Very weak (reordering without consideration for dependencies)
Alpha

Because double locking is not thread safe in general then it should never be used.

Note that not being thread safe means that it *can* fail - it does not mean that it *will* fail everytime or that it *will* fail often. But Murphys law applied says that it will work 1 billion times in test and fail in production.

DoubleLockSingleton.java:

package singleton;

// **** double lock singleton pattern is not thread safe - never use it ****
public class DoubleLockSingleton {
    private static DoubleLockSingleton instance = null;
    private int someState;
    private DoubleLockSingleton() {
        someState = 123;
    }
    public static DoubleLockSingleton getInstance() {
        if(instance == null) {
            synchronized(DoubleLockSingleton.class) {
                if(instance == null) {
                    instance = new DoubleLockSingleton();
                }
            }
        }
        return instance;
    }
    public void someMethod() {
        System.out.println(someState);
    }
}

DoubleLockSingleton.cs:

using System;

namespace Singleton
{
    // **** double lock singleton pattern is not thread safe - never use it ****
    public class DoubleLockSingleton
    {
        private static DoubleLockSingleton instance;
        private static readonly object mylock = new object();
        private int someState;
        private DoubleLockSingleton() 
        {
            someState = 123;
        }
        public static DoubleLockSingleton Instance
        {
            get
            {
                if(instance == null)
                {
                    lock(mylock)
                    {
                        if(instance == null)
                        {
                            instance = new DoubleLockSingleton();
                        }
                    }
                }
                return instance;
            }
        }
        public void SomeMethod()
        {
            Console.WriteLine(someState);
        }
    }
}

DoubleLockSingleton.vb:

Imports System

Namespace Singleton
    ' **** double lock singleton pattern is not thread safe - never use it ****
    Public Class DoubleLockSingleton
        Private Shared m_instance As DoubleLockSingleton
        Private Shared ReadOnly mylock As New Object()
        Private someState As Integer
        Private Sub New()
            someState = 123
        End Sub
        Public Shared ReadOnly Property Instance() As DoubleLockSingleton
            Get
                If m_instance Is Nothing Then
                    SyncLock mylock
                        If m_instance Is Nothing Then
                            m_instance = New DoubleLockSingleton()
                        End If
                    End SyncLock
                End If
                Return m_instance
            End Get
        End Property
        Public Sub SomeMethod()
            Console.WriteLine(someState)
        End Sub
    End Class
End Namespace

DoubleLockSingleton.h:

#ifndef DOUBLELOCK_SINGLETON_H
#define DOUBLELOCK_SINGLETON_H

#include <iostream>

using namespace std;


// **** double lock singleton pattern is not thread safe - never use it ****
class DoubleLockSingleton
{
private:
    static DoubleLockSingleton* instance;
    int SomeState;
    DoubleLockSingleton() { SomeState = 123; }
    DoubleLockSingleton(const DoubleLockSingleton& original) { };
    DoubleLockSingleton& operator=(const DoubleLockSingleton& original) { return *this; };
public:
    static DoubleLockSingleton* Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

DoubleLockSingleton.cpp:

#include <cstddef>

using namespace std;

#include "Lock.h"

#include "DoubleLockSingleton.h"

DoubleLockSingleton* DoubleLockSingleton::instance = NULL;

DoubleLockSingleton* DoubleLockSingleton::Instance()
{
    if(instance == NULL)
    {
        Lock mylock;
        if(instance == NULL)
        {
            instance = new DoubleLockSingleton();
        }
    }
    return instance;
}

Lock.h:

#ifndef LOCK_H
#define LOCK_H

void lock_setup();
void lock_destroy();

class Lock
{
public:
    Lock();
    virtual ~Lock();
};

#endif

Lock.cpp:

#ifdef WIN32_THREADS
#include <windows.h>
static CRITICAL_SECTION cs;
#elif POSIX_THREADS
#include <pthread.h>
static pthread_mutex_t mtx;
#else
#error "No threading model specified"
#endif

#include "Lock.h"

void lock_setup()
{
#ifdef WIN32_THREADS
    InitializeCriticalSection(&cs);        
#endif        
#ifdef POSIX_THREADS
    pthread_mutex_init(&mtx, NULL);
#endif
}

void lock_destroy()
{
#ifdef WIN32_THREADS
    DeleteCriticalSection(&cs);        
#endif        
#ifdef POSIX_THREADS
    pthread_mutex_destroy(&mtx);
#endif
}

Lock::Lock()
{
#ifdef WIN32_THREADS
    EnterCriticalSection(&cs);        
#endif        
#ifdef POSIX_THREADS
    pthread_mutex_lock(&mtx);
#endif
}

Lock::~Lock()
{
#ifdef WIN32_THREADS
    LeaveCriticalSection(&cs);        
#endif        
#ifdef POSIX_THREADS
    pthread_mutex_unlock(&mtx);
#endif
}

DoubleLockSingleton11.h:

#ifndef DOUBLELOCK_SINGLETON_11_H
#define DOUBLELOCK_SINGLETON_11_H

#include <iostream>

using namespace std;

// **** double lock singleton pattern is not thread safe - never use it ****
class DoubleLockSingleton11
{
private:
    static DoubleLockSingleton11* instance;
    int SomeState;
    DoubleLockSingleton11() { SomeState = 123; }
public:
    DoubleLockSingleton11(const DoubleLockSingleton11& original) = delete;
    DoubleLockSingleton11& operator=(const DoubleLockSingleton11& original) = delete;
    static DoubleLockSingleton11& Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

DoubleLockSingleton11.cpp:

#include <cstddef>
#include <mutex>

using namespace std;

static mutex mymutex;

#include "DoubleLockSingleton11.h"

DoubleLockSingleton11* DoubleLockSingleton11::instance = nullptr;

DoubleLockSingleton11& DoubleLockSingleton11::Instance()
{
    if(instance == nullptr)
    {
        lock_guard<mutex> mylock(mymutex);
        if(instance == nullptr)
        {
            instance = new DoubleLockSingleton11();
        }
    }
    return *instance;
}

Double locking with volatile solution:

One can attempt to fix the double locking solution by adding volatile declarations.

class Singleton {
    static volatile Singleton instance = null
    Singleton GetInstance() {
        if(instance == null) {
            only one thread at a time {
                if(instance == null) {
                    instance = new Singleton()
                }
            }
        }
        return instance
    }
    ...
}

The result is thread safe in Java version 5+ and in .NET, but not thread safe in Java versions before 5 and in C++.

All due to differences in volatile semantics.

VolatileSingleton.java:

package singleton;

public class VolatileSingleton {
    private static volatile VolatileSingleton instance = null;
    private int someState;
    private VolatileSingleton() {
        someState = 123;
    }
    public static VolatileSingleton getInstance() {
        if(instance == null) {
            synchronized(VolatileSingleton.class) {
                if(instance == null) {
                    instance = new VolatileSingleton();
                }
            }
        }
        return instance;
    }
    public void someMethod() {
        System.out.println(someState);
    }
}

VolatileSingleton.cs:

using System;

namespace Singleton
{
    public class VolatileSingleton
    {
        private static volatile VolatileSingleton instance;
        private static readonly object mylock = new object();
        private int someState;
        private VolatileSingleton() 
        {
            someState = 123;
        }
        public static VolatileSingleton Instance
        {
            get
            {
                if(instance == null)
                {
                    lock(mylock)
                    {
                        if(instance == null)
                        {
                            instance = new VolatileSingleton();
                        }
                    }
                }
                return instance;
            }
        }
        public void SomeMethod()
        {
            Console.WriteLine(someState);
        }
    }
}

VolatileSingleton.vb:

Imports System

Namespace Singleton
    Public Class VolatileSingleton
        Private Shared m_instance As VolatileSingleton
        Private Shared ReadOnly mylock As New Object()
        Private someState As Integer
        Private Sub New()
            someState = 123
        End Sub
        Public Shared ReadOnly Property Instance() As VolatileSingleton
            Get
                If m_instance Is Nothing Then
                    SyncLock mylock
                        If m_instance Is Nothing Then
                            m_instance = New VolatileSingleton()
                        End If
                    End SyncLock
                End If
                Return m_instance
            End Get
        End Property
        Public Sub SomeMethod()
            Console.WriteLine(someState)
        End Sub
    End Class
End Namespace

VolatileSingleton.h:

#ifndef Volatile_SINGLETON_H
#define Volatile_SINGLETON_H

#include <iostream>

using namespace std;


// **** double lock with volatile singleton pattern is not thread safe - never use it ****
class VolatileSingleton
{
private:
    static volatile VolatileSingleton* volatile instance;
    int SomeState;
    VolatileSingleton() { SomeState = 123; }
    VolatileSingleton(const VolatileSingleton& original) { };
    VolatileSingleton& operator=(const VolatileSingleton& original) { return *this; };
public:
    static volatile VolatileSingleton* volatile Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

VolatileSingleton.cpp:

#include <cstddef>

using namespace std;

#include "Lock.h"

#include "VolatileSingleton.h"

volatile VolatileSingleton* volatile VolatileSingleton::instance = NULL;

volatile VolatileSingleton* volatile VolatileSingleton::Instance()
{
    if(instance == NULL)
    {
        Lock mylock;
        if(instance == NULL)
        {
            volatile VolatileSingleton* volatile temp = new volatile VolatileSingleton();
            instance = temp;
        }
    }
    return instance;
}

Lock.h:

#ifndef LOCK_H
#define LOCK_H

void lock_setup();
void lock_destroy();

class Lock
{
public:
    Lock();
    virtual ~Lock();
};

#endif

Lock.cpp:

#ifdef WIN32_THREADS
#include <windows.h>
static CRITICAL_SECTION cs;
#elif POSIX_THREADS
#include <pthread.h>
static pthread_mutex_t mtx;
#else
#error "No threading model specified"
#endif

#include "Lock.h"

void lock_setup()
{
#ifdef WIN32_THREADS
    InitializeCriticalSection(&cs);        
#endif        
#ifdef POSIX_THREADS
    pthread_mutex_init(&mtx, NULL);
#endif
}

void lock_destroy()
{
#ifdef WIN32_THREADS
    DeleteCriticalSection(&cs);        
#endif        
#ifdef POSIX_THREADS
    pthread_mutex_destroy(&mtx);
#endif
}

Lock::Lock()
{
#ifdef WIN32_THREADS
    EnterCriticalSection(&cs);        
#endif        
#ifdef POSIX_THREADS
    pthread_mutex_lock(&mtx);
#endif
}

Lock::~Lock()
{
#ifdef WIN32_THREADS
    LeaveCriticalSection(&cs);        
#endif        
#ifdef POSIX_THREADS
    pthread_mutex_unlock(&mtx);
#endif
}

VolatileSingleton11.h:

#ifndef VOLATILE_SINGLETON_11_H
#define VOLATILE_SINGLETON_11_H

#include <iostream>

using namespace std;

// **** double lock with volatile singleton pattern is not thread safe - never use it ****
class VolatileSingleton11
{
private:
    static volatile VolatileSingleton11* volatile instance;
    int SomeState;
    VolatileSingleton11() { SomeState = 123; }
public:
    VolatileSingleton11(const VolatileSingleton11& original) = delete;
    VolatileSingleton11& operator=(const VolatileSingleton11& original) = delete;
    static volatile VolatileSingleton11& Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

VolatileSingleton11.cpp:

#include <cstddef>
#include <mutex>

using namespace std;

static mutex mymutex;

#include "VolatileSingleton11.h"

volatile VolatileSingleton11* volatile VolatileSingleton11::instance = nullptr;

volatile VolatileSingleton11& VolatileSingleton11::Instance()
{
    if(instance == nullptr)
    {
        lock_guard<mutex> mylock(mymutex);
        if(instance == nullptr)
        {
            volatile VolatileSingleton11* volatile temp = new VolatileSingleton11();
            instance = temp;
        }
    }
    return *instance;
}

Memory barrier solution:

Another attempt to fix the double checking solution is to add explicit memory barriers.

class Singleton {
    static Singleton instance = null
    Singleton GetInstance() {
        if(instance == null) {
            only one thread at a time {
                if(instance == null) {
                    temp = new Singleton()
                    memory_barrier
                    instance = temp
                }
            }
        }
        return instance
    }
    ...
}

This is thread safe in .NET and C++ 11+. It is thread safe but undocumented, unsupported and promised to go away in Java.

Do not attempt to use this solution in Java.

MemBarrierSingleton11.h:

#ifndef MEMBARRIER_SINGLETON_11_H
#define MEMBARRIER_SINGLETON_11_H

#include <iostream>
#include <atomic>

using namespace std;

class MemBarrierSingleton11
{
private:
    static atomic<MemBarrierSingleton11*> instance;
    int SomeState;
    MemBarrierSingleton11() { SomeState = 123; }
public:
    MemBarrierSingleton11(const MemBarrierSingleton11& original) = delete;
    MemBarrierSingleton11& operator=(const MemBarrierSingleton11& original) = delete;
    static MemBarrierSingleton11& Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

MemBarrierSingleton11.cpp:

#include <cstddef>
#include <mutex>
#include <atomic>

using namespace std;

static mutex mymutex;

#include "MemBarrierSingleton11.h"

atomic<MemBarrierSingleton11*> MemBarrierSingleton11::instance;

MemBarrierSingleton11& MemBarrierSingleton11::Instance()
{
    MemBarrierSingleton11 *temp = instance.load();
    if(temp == nullptr)
    {
        lock_guard<mutex> mylock(mymutex);
        temp = instance.load();
        if(temp == nullptr)
        {
            temp = new MemBarrierSingleton11();
            instance.store(temp);
        }
    }
    return *temp;
}

MemBarrierXSingleton11.h:

#ifndef MEMBARRIERX_SINGLETON_11_H
#define MEMBARRIERX_SINGLETON_11_H

#include <iostream>
#include <atomic>

using namespace std;

class MemBarrierXSingleton11
{
private:
    static atomic<MemBarrierXSingleton11*> instance;
    int SomeState;
    MemBarrierXSingleton11() { SomeState = 123; }
public:
    MemBarrierXSingleton11(const MemBarrierXSingleton11& original) = delete;
    MemBarrierXSingleton11& operator=(const MemBarrierXSingleton11& original) = delete;
    static MemBarrierXSingleton11& Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

MemBarrierXSingleton11.cpp:

#include <cstddef>
#include <mutex>
#include <atomic>

using namespace std;

static mutex mymutex;

#include "MemBarrierXSingleton11.h"

atomic<MemBarrierXSingleton11*> MemBarrierXSingleton11::instance;

MemBarrierXSingleton11& MemBarrierXSingleton11::Instance()
{
    MemBarrierXSingleton11 *temp = instance.load(memory_order_acquire);
    if(temp == nullptr)
    {
        lock_guard<mutex> mylock(mymutex);
        temp = instance.load(memory_order_relaxed);
        if(temp == nullptr)
        {
            temp = new MemBarrierXSingleton11();
            instance.store(temp, memory_order_release);
        }
    }
    return *temp;
}

Java 8 added 3 memory fence methods to the infamous sun.misc.Unsafe class.

Note that the Java compiler will give warnings for the use of the sun.misc.Unsafe class.

MemBarrierSingleton.java:

package singleton;

public class MemBarrierSingleton {
    private static sun.misc.Unsafe unsafe;
    static {
        try {
            java.lang.reflect.Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            unsafe = (sun.misc.Unsafe)f.get(null);
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    }
    private static MemBarrierSingleton instance = null;
    private int someState;
    private MemBarrierSingleton() {
        someState = 123;
    }
    public static MemBarrierSingleton getInstance() {
        if(instance == null) {
            synchronized(MemBarrierSingleton.class) {
                if(instance == null) {
                    MemBarrierSingleton temp = new MemBarrierSingleton();
                    unsafe.fullFence();
                    instance = temp;
                }
            }
        }
        return instance;
    }
    public void someMethod() {
        System.out.println(someState);
    }
}

MemBarrierSingleton.cs:

using System;
using System.Threading;

namespace Singleton
{
    public class MemBarrierSingleton
    {
        private static MemBarrierSingleton instance;
        private static readonly object mylock = new object();
        private int someState;
        private MemBarrierSingleton() 
        {
            someState = 123;
        }
        public static MemBarrierSingleton Instance
        {
            get
            {
                if(instance == null)
                {
                    lock(mylock)
                    {
                        if(instance == null)
                        {
                            MemBarrierSingleton temp = new MemBarrierSingleton();
                            Thread.MemoryBarrier();
                            instance = temp;
                        }
                    }
                }
                return instance;
            }
        }
        public void SomeMethod()
        {
            Console.WriteLine(someState);
        }
    }
}

MemBarrierSingleton.vb:

Imports System
Imports System.Threading

Namespace Singleton
    Public Class MemBarrierSingleton
        Private Shared m_instance As MemBarrierSingleton
        Private Shared ReadOnly mylock As New Object()
        Private someState As Integer
        Private Sub New()
            someState = 123
        End Sub
        Public Shared ReadOnly Property Instance() As MemBarrierSingleton
            Get
                If m_instance Is Nothing Then
                    SyncLock mylock
                        If m_instance Is Nothing Then
                            Dim temp As MemBarrierSingleton = New MemBarrierSingleton()
                            Thread.MemoryBarrier()
                            m_instance = temp
                        End If
                    End SyncLock
                End If
                Return m_instance
            End Get
        End Property
        Public Sub SomeMethod()
            Console.WriteLine(someState)
        End Sub
    End Class
End Namespace

Holder class solution:

An alternative approach is to use a holder class for the static initialization. This implementation is attributed to Bill Pugh.

This solution is thread safe.

HolderSingleton.java:

package singleton;

public class HolderSingleton {
    private static class HolderSingletonHelper {
        private static final HolderSingleton instance = new HolderSingleton();
    }
    private int someState;
    private HolderSingleton() {
        someState = 123;
    }
    public static HolderSingleton getInstance() {
        return HolderSingletonHelper.instance;
    }
    public void someMethod() {
        System.out.println(someState);
    }
}

HolderSingleton.cs:

using System;

namespace Singleton
{
    public class HolderSingleton
    {
        private class HolderSingletonHelper
        {
            internal static readonly HolderSingleton instance = new HolderSingleton();
        }
        private int someState;
        private HolderSingleton() 
        {
            someState = 123;
        }
        public static HolderSingleton Instance
        {
            get
            {
                return HolderSingletonHelper.instance;
            }
        }
        public void SomeMethod()
        {
            Console.WriteLine(someState);
        }
    }
}

HolderSingleton.vb:

Imports System

Namespace Singleton
    Public Class HolderSingleton
        Private Class HolderSingletonHelper
            Friend Shared ReadOnly instance As New HolderSingleton()
        End Class
        Private someState As Integer
        Private Sub New()
            someState = 123
        End Sub
        Public Shared ReadOnly Property Instance() As HolderSingleton
            Get
                Return HolderSingletonHelper.instance
            End Get
        End Property
        Public Sub SomeMethod()
            Console.WriteLine(someState)
        End Sub
    End Class
End Namespace

C++ 11 once_flag and call_once solution:

C++ 11 has a feature specific designed to ensure that a call only is made once.

This solution is thread safe.

CallOnceSingleton11.h:

#ifndef CALLONCE_SINGLETON_11_H
#define CALLONCE_SINGLETON_11_H

#include <iostream>
#include <mutex>

using namespace std;

class CallOnceSingleton11
{
private:
    static CallOnceSingleton11* instance;
    int SomeState;
    CallOnceSingleton11() { SomeState = 123; }
    static once_flag flag;
    static void Init();
public:
    CallOnceSingleton11(const CallOnceSingleton11& original) = delete;
    CallOnceSingleton11& operator=(const CallOnceSingleton11& original) = delete;
    static CallOnceSingleton11& Instance();
    void SomeMethod() { cout << SomeState << endl; }
};

#endif

CallOnceSingleton11.cpp:

#include <cstddef>
#include <mutex>

using namespace std;

#include "CallOnceSingleton11.h"

once_flag CallOnceSingleton11::flag;

CallOnceSingleton11* CallOnceSingleton11::instance = nullptr;

void CallOnceSingleton11::Init()
{
    instance = new CallOnceSingleton11();
}

CallOnceSingleton11& CallOnceSingleton11::Instance()
{
    call_once(flag, Init);
    return *instance;
}

.NET Lazy<T> solution:

.NET 4.0 added a Lazy<T> class that can be used as a solution.

This solution is thread safe.

LazySingleton.cs:

using System;

namespace Singleton
{
    public class LazySingleton
    {
        private static readonly Lazy<LazySingleton> lazy_instance = new Lazy<LazySingleton>(() => new LazySingleton());
        private int someState;
        private LazySingleton() 
        {
            someState = 123;
        }
        public static LazySingleton Instance
        {
            get
            {
                return lazy_instance.Value;
            }
        }
        public void SomeMethod()
        {
            Console.WriteLine(someState);
        }
    }
}

LazySingleton.vb:

Imports System

Namespace Singleton
    Public Class LazySingleton
        Private Shared ReadOnly lazy_instance As New Lazy(Of LazySingleton)(Function() New LazySingleton())
        Private someState As Integer
        Private Sub New()
            someState = 123
        End Sub
        Public Shared ReadOnly Property Instance() As LazySingleton
            Get
                Return lazy_instance.Value
            End Get
        End Property
        Public Sub SomeMethod()
            Console.WriteLine(someState)
        End Sub
    End Class
End Namespace

Conclusion:

Most likely nobody need a solution for this problem.

But if they do then plenty of solutions exist.

I would pick the synchronized solution, because it is the most natural solution and therefore the most readable solution. And I do not care about that tiny extra overhead. My measurements say that the overhead is about 10-20 ns in Java, 30-60 ns in .NET and 0-200 ns in C++. That is nothing.

Article history:

Version Date Description
1.0 June 13th 2024 Initial version

Other articles:

See list of all articles here

Comments:

Please send comments to Arne Vajhøj