Saturday, November 8, 2008

Simply Singleton

We all know how objects are instantiated right? Maybe not everyone? Let's go through a quick refresher.

Objects are instantiated by using the new keyword. The new keyword allows you to create a new instance of an object, and to specify parameters to the class's constructor. You can specify no parameters, in which case the blank constructor (also known as the default constructor) is invoked. Constructors can have access modifiers, like public and private, which allow you to control which classes have access to a constructor. So to prevent direct instantiation, we create a private default constructor, so that other classes can't create a new instance.

We'll start with the class definition, for a SingletonObject class. Next, we provide a default constructor that is marked as private. No actual code needs to be written, but you're free to add some initialization code if you'd like.

public class SingletonObject
{
private SingletonObject()
{
// no code req'd
}
}

So far so good. But unless we add some further code, there'll be absolutely no way to use the class. We want to prevent direct instantiation, but we still need to allow a way to get a reference to an instance of the singleton object.

Getting an instance of the singleton

We need to provide an accessor method, that returns an instance of the SingletonObject class but doesn't allow more than one copy to be accessed. We can manually instantiate an object, but we need to keep a reference to the singleton so that subsequent calls to the accessor method can return the singleton (rather than creating a new one). To do this, provide a public static method called getSingletonObject(), and store a copy of the singleton in a private member variable.

public class SingletonObject
{
private SingletonObject()
{
// no code req'd
}

public static SingletonObject getSingletonObject()
{
if (ref == null)
// it's ok, we can call this constructor
ref = new SingletonObject();
return ref;
}

private static SingletonObject ref;
}

So far, so good. When first called, the getSingletonObject() method creates a singleton instance, assigns it to a member variable, and returns the singleton. Subsequent calls will return the same singleton, and all is well with the world. You could extend the functionality of the singleton object by adding new methods, to perform the types of tasks your singleton needs. So the singleton is done, right? Well almost.....

Preventing thread problems with your singleton

We need to make sure that threads calling the getSingletonObject() method don't cause problems, so it's advisable to mark the method as synchronized. This prevents two threads from calling the getSingletonObject() method at the same time. If one thread entered the method just after the other, you could end up calling the SingletonObject constructor twice and returning different values. To change the method, just add the synchronized keyword as follows to the method declaration :-

public static synchronized
SingletonObject getSingletonObject()

Are we finished yet?

There, finished. A singleton object that guarantees one instance of the class, and never more than one. Right? Well.... not quite. Where there's a will, there's a way - it is still possible to evade all our defensive programming and create more than one instance of the singleton class defined above. Here's where most articles on singletons fall down, because they forget about cloning. Examine the following code snippet, which clones a singleton object.

public class Clone
{
public static void main(String args[])
throws Exception
{
// Get a singleton
SingletonObject obj =
SingletonObject.getSingletonObject();

// Buahahaha. Let's clone the object
SingletonObject clone =
(SingletonObject) obj.clone();

}
}

Okay, we're cheating a little here. There isn't a clone() method defined in SingletonObject, but there is in the java.lang.Objectclass which it is inherited from. By default, the clone() method is marked as protected, but if your SingletonObject extends another class that does support cloning, it is possible to violate the design principles of the singleton. So, to be absolutely positively 100% certain that a singleton really is a singleton, we must add a clone() method of our own, and throw a CloneNotSupportedException if anyone dares try!

Here's the final source code for a SingletonObject, which you can use as a template for your own singletons.

public class SingletonObject
{
private SingletonObject()
{
// no code req'd
}

public static SingletonObject getSingletonObject()
{
if (ref == null)
// it's ok, we can call this constructor
ref = new SingletonObject();
return ref;
}

public Object clone()
throws CloneNotSupportedException
{
throw new CloneNotSupportedException();
// that'll teach 'em
}


private static SingletonObject ref;
}


Preventing direct instantiation

//sample code
package com.test.corejava;

/**
*
* @author seetharam
*/
public class TestSingleton {

private static TestSingleton instance;

// Private constructor suppresses generation of a (public) default constructor

private TestSingleton() {

// logic code is not req'd
}



public static TestSingleton getInstance() {

//acquiring the lock to the class's obj
synchronized (TestSingleton.class) {

if (instance == null) {

instance = new TestSingleton();
}
}

return instance;

}

public Object clone() throws CloneNotSupportedException
{
throw new CloneNotSupportedException();
// that'll teach 'em
}
}


Summary

A singleton is an class that can be instantiated once, and only once. This is a fairly unique property, but useful in a wide range of object designs. Creating an implementation of the singleton pattern is fairly straightforward - simple block off access to all constructors, provide a static method for getting an instance of the singleton, and prevent cloning.

No comments: