Skip to the on-demand holder pattern.
The Singleton Pattern, one of the patterns defined by the Gang of 4, restricts the instantiation of a class to a single object. It's useful to coordinate actions across an entire system, access to a hardware interface, logger, configuration file, cache, etc.
Pros
Cons
In terms of beginning Java samples you have the implementation of a singleton. This is the simplest form, but it would be disastrous in a multithreaded situation. (See the second article for solutions to questions like this.)
public class Singleton { // holds but one instance of this class private static Singleton instance; // private constructor prevents any callers from instantiating private Singleton() { System.out.println( "Constructing new instance of Singleton..." ); } // provide public access to the single instance public static Singleton getInstance() { // lazy initialization... if ( instance == null ) instance = new Singleton(); return instance; } public void print() { System.out.println( "Inside singleton!" ); } }
If it's not important to construct the class instance lazily, it's possible to let Java handle its construction ahead of time. This would be thread-safe in most situations. Modern Java thought is that there is no real advantage to lazy initialization in preference to "early" initialization unless there is a very real possibility that the class will simply never be instantiated. Here's the preferred, "early" version.
public class Singleton { private static final Singleton instance = new Singleton(); private Singleton() { System.out.println( "Constructing new instance of Singleton..." ); } public static Singleton getInstance() { if ( instance == null ) instance = new Singleton(); return instance; } public void print() { System.out.println( "Inside singleton!" ); } }
Here's how to spruce it up to be thread-safe, using the synchronized keyword.
public class Singleton { private static Singleton instance; private Singleton() { System.out.println( "Constructing new instance of Singleton..." ); } public static Singleton getInstance() { synchronized( Singleton.class ) { if( instance == null ) instance = new Singleton(); } return instance; } public void print() { System.out.println( "Inside singleton!" ); } }
Goetz' Java Concurrency In Practice (pp. 348,9) says double-locking isn't good practice and since at least Java 5, the JVM start-up speed is no longer so slow as to make lazy initialization of an object that's going to be used an important consideration.
Bracketing the synchronization (double-locking) in a check for null instance (instead of proceeding directly with the used of synchronized) hoping for the advantage of reducing the use and overhead of Java synchronization to just the first time object instantiation is contested (and satisfied) so it will not be a burden again in the life of the (singleton) object would only work reliably beginning in Java 5 AND with the use of the volatile keyword on the static instance.
private volatile static Singleton instance; . . . public static Singleton getInstance() { if( instance == null ) { synchronized( Singleton.class ) { if( instance == null ) instance = new Singleton(); } return instance; }
If the class is cloned, however, there will be another instance of it. The only way to prevent that would be to override clone and throw an exception.
import java.lang.CloneNotSupportedException; . . . @Override public Object clone() { throw new CloneNotSupportedException( "Singleton-only; no cloning!" ); } }
It would still be possible to serialize/deserialize and get a non-unique instance. To prevent that, the class could be made an enumeration and Java would prevent it.
...what Wikipedia calls this, anyway. This is how I began to code singletons at some point.
This is a pattern augmenting the singleton that is formally designed to improve lazy loading. It works in single- or serial- as well as concurrent (multithreaded) situations. Its trick is to implement an inner class to perform initialization based on the specified initialization phase of execution in the JVM.
Then the outer or principal class is loaded by the JVM, it's initialized. Since, unlike most traditional singleton implementations, there are no static variables, this first initialization does little to nothing.
On first initialization of Something, the holder inner class is not initialized right off. This only happens the first time a calling application thread happens to wander through the outer class' getInstance() method. Only at that point will the JVM load and initialize SomethingHolder. Since the class initialization phase is guaranteed by the Java Language Specification to be strictly serial, which is to say, not concurrent, no explicit synchronization is necessary for getInstance(). Since the JVM writes the variable INSTANCE in this serial operation, all subsequent invocations of getInstance(), concurrent or not, will return precisely the correctly initialized INSTANCE without additional or explicit synchronization overhead.
This version of the singleton might be avoided if the construction of INSTANCE is likely to fail, but failure to initialize is a criticism of singleton pattern implementations in general.
In the code below, what's in bold is where the traditional singleton implementation is rejoined. Notice that Something's constructor remains private. It's called only by the holder class. The private constructor can do some real things as exemplified by the later real-world example.
public class Something { private static class SomethingHolder { private static final Something INSTANCE = new Something(); } private Something() { } public static Something getInstance() { return SomethingHolder.INSTANCE; } . . . }
...of a data-access object class implementing accounts in a MongoDB database. This shows a more, useful, real-world context in the implementation.
public class AccountDao extends BaseDao< Account > { private static final Logger log = Logger.getLogger( AccountDao.class ); private MongoDB mongoDB; private Datastore datastore; private static class AccountDaoHolder { public static final AccountDao INSTANCE = new AccountDao(); } private AccountDao() { mongoDB = new MongoDB( "accountdb", "accounts" ); datastore = mongoDB.getMorphiastore(); } public static AccountDao getInstance() { log.trace( "AccountDao getInstance()" ); return AccountDaoHolder.INSTANCE; } public DBCollection getCollection() { return mongoDB.getCollection(); } public Datastore getDatastore() { return datastore; } public Class< Account > getClazz() { return Account.class; } public Account create( Account entity ) { datastore.save( entity ); return entity; } public List< Account > findByIdentity( String identity ) { Query< Account > query = datastore.createQuery( Account.class ) .filter( "identities", identity ); return query.asList(); } public List< Account > readAll() { Query< Account > query = datastore.createQuery( Account.class ); query.field( "canceled" ).equals( false ); return query.asList(); } . . . }