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.
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.
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
}
...
}
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.
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%.
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 singleton pattern has been criticized for several reasons:
But let us take a look at each of the reasons.
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:
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.
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:
This argument is valid and require both justification and mitigation.
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.
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.
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.
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:
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;
}
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:
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:
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;
}
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;
}
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
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 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 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
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.
Version | Date | Description |
---|---|---|
1.0 | June 13th 2024 | Initial version |
See list of all articles here
Please send comments to Arne Vajhøj
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.