Friday, March 12, 2010

Singleton design pattern

It is conceptually the simplest design pattern and many argue that it is actually an anti-pattern and continues to exist within computing courses because GoF specified it in their seminal work and it offers easy introduction to the subject of design patterns. Controversial it may well be but it has a useful purpose when we do genuinely need just one object of a class. Obviously the logger is the primary example.

The design is simple:

package raj;

class TestSingleton {
public static void main(String[] arg) {
Singleton s = Singleton.getInstance();
System.out.println(s.toString());
s.setVal(100);
Singleton s2 = Singleton.getInstance();
System.out.println(s2.toString());
System.out.println(s2.getVal());
}
}

public class Singleton {

private static Singleton singletonObj;

private Singleton() {
}
private int val = 0;

public int getVal() {
return val;
}

public void setVal(int val) {
this.val = val;
}

public static Singleton getInstance() {
if (singletonObj == null) {
singletonObj = new Singleton();
}
return singletonObj;
}
}

It relies on having a private constructor and public static interface to provide the object. We can make this design thread-safe by synchronizing the getInstance() method:

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

However, this approach would considerably slow down the access to the object as synchronization can be painfully slow and is only needed during the first create. To over come this we may eschew lazy instantiation of the object and change our Singleton class to the following to let the class loader take the responsibility for instantiation:

public class Singleton {

private static Singleton singletonOb = new Singleton();j;

private Singleton() {
}
private int val = 0;

public int getVal() {
return val;
}

public void setVal(int val) {
this.val = val;
}

public static Singleton getInstance() {
return singletonObj;
}
}

This is great! But if the objected created is a scarce resource and is never used then it obviously is wasteful. A thread-safe compromise solution would be to use double-checked locking:

public static Singleton getInstance() {
if (singletonObj == null) {
synchronized (Singleton.class) {
if (singletonObj == null) singletonObj = new Singleton();
}}
return singletonObj;
}

Now we take the synchronization hit just during the create but there is still a small overhead of an extra conditional check during every access. Also note that we cannot use synchronized(this) as we are locking from within a static context so need the class literal Singleton.class.

No comments:

Post a Comment