Java, Tips

How to make a Perfect Singleton?


In the previous post I mentioned about writing a post about how to write a perfect Singleton class without using Double Checked Locking. In this post I am going to discuss the same topic.

It seems to me that there are many ways to implement a Java Singleton which are listed below:

If you DO NOT NEED Lazy Initialization

and most of the time you don’t, then simply use a static member and initialize it right there (or in a static block). The class loader guarantees that only one thread will perform any class’s static initialization. By the way, if the only accessible static field or method is getInstance() and no code directly accesses Singleton.class or invokes Class.forName(“Singleton”), you essentially get lazy initialization for free thanks to the class loader.

public class Singleton {
	private static final Singleton instance = new Singleton();
	public static Singleton getInstance() {
		return instance;
	}
}

If you NEED lazy initialization

and you are OK with the overhead of always acquiring the mutex, then use this form:

public class Singleton {
	private static final Singleton instance;

	public synchronized static Singleton getInstance() {
	if (instance == null) {
		instance = new Singleton();
	}

	return instance;
	}
}

If you NEED lazy initialization

and you CANNOT stomach the overhead of always acquiring the mutex (this is the least likely case), then leverage the class loader’s behavior to guard the construction of the singleton. This solution relies on the fact that a class will not be loaded and initialized until referenced. The static inner class Instance will only be loaded when the outer class’s getInstance() method references Instance.value.

public class Singleton {
	private static class Instance {
		static final Singleton value = new Singleton();
	}

	public static Singleton getInstance() {
		return Instance.value;
	}
}

The inner class idiom is good. The Singleton is essentially a Factory and the instance itself a product of the Factory, so it is a separate abstraction. The Declaration suggests using a separate class but doesn’t mention the possibility of an inner class – an oversight possibly. Java inner classes don’t get the respect they deserve, they can be quite useful.

Nice solution, but is that class loading behaviour guaranteed in the Java specifications?
The Java Language Standard states that class loaders can prefetch or otherwise group the loading of classes. So, no the behavior in option 3 above is not guaranteed. However, it generally holds true since most class loaders do not prefetch classes.

Using Enums in Java 5 for Singleton

As Joshua Bloch suggested in his book Effect Java, 2nd Edition we can use Enums for making a Singleton and with it we

Summary of what has been said else where

  • The compiler / JVM can rearrange code within synchronized blocks for optimisation.
  • The compiler / JVM can move code into a synchronized block for optimisation.
  • The compiler / JVM cannot move code out of a synchronized block.
  • Threads can store local copies of variables that are not declared volatile or protected by a synchronized block so may not see changes made by other threads. (And volatile has a known bug prior to the implementation of JSR-133 – it doesn’t appear to actually do anything).

For these reasons you have to really know what you’re doing when trying to avoid synchronisation, and usually the only truly safe approach is to synchronise around the whole thing that needs to be thread safe. The extra cost is on the order of microseconds, and there are usually far better places to look to improve application performance.

About these ads
Standard

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s