Singleton Pattern: Part 3 Double Checked Locking
In the last post on Singleton Patterns, We looked into a thread safe mechanism to create singleton objects. The concept works well enough for most systems. However, when this becomes a hot section (heavily accessed) in your code, we will begin to hit performance problems. Here's why: Lets say we have a high performant system, with 50-100 threads working around like magic, sharing tasks and running as fast as possible. Lets say that all the threads hit this hot section very often. This will result in the hot section being a real bottle neck, synchronizing and slowing down all the threads. Every thread enters this critical section and blocks every other thread from using this section. But is this really required? The 'clever' double locking system 'tries' to fix this problem.
Instead of locking down the critical section and blocking all the threads, this technique gives a chance for the threads to asynchronously check, whether or not it needs to enter this section in the first place. If it does (when instance != null), it then locks the section and proceeds in a normal thread safe manner where it does the second check. So the name, Double Checked Locking.
class Singleton
{
private:
static Singleton instance;
protected Singleton()
{
}
public static Singleton CreateInstance()
{
if(instance == null) //first check
{
// Use a mutex locking mechanism
// that suits your system
LockCriticalSection();
if (instance == null) //second check
{
instance = new Singleton();
}
UnLockCriticalSection();
}
return instance;
}
}
Note: If you are using Java to implement this, beware that there are issues in Java's memory model that prevent this technique from working correctly. This issue is however, fixed. So make sure you have the latest JDK if you plan to use this in your code. In a later post, I will go over the bug in JDK, more specifically in Java's memory model that causes this problem.
Comments
Double-Check Lock Pattern
Double-Check Lock Pattern (DCLP) used to be considered pretty clever, and was asked about in C++ interviews. However, it can't be implemented in a reliable, portable (compilers, platforms) way, even if you use the volatile keyword six ways 'til Sunday, and may behave differently on uniprocessor or multiprocessor architectures. Thus, it shouldn't be used, and probably shouldn't be asked about in interviews. The key is for callers to know that accessing the singleton is expensive and writing appropriate code. Also, try to avoid "singletonitis". Not everything needs to be a singleton in the first place. Prefer explicit object semantics to the "jump wire" approach - if you have a method called "doStuff()" that makes use of a singleton... printer, for example, I'd much rather see "doStuff(const Printer&);" in the header file. This article published jointly by Scott Meyers and Andrei Alexandrescu goes a long way to explaining the dangers of DCLP better than I can: http://www.aristeia.com/Papers/DDJJulAug2004revised.pdf