Tuesday, April 27, 2010

Simply Singleton

Singleton Design Pattern: Ensure that only one instance of a class is created;
Provide a global point of access to the object.


public class SimpleSingleton {

private static SimpleSingleton instance = null;

protected SimpleSingleton() {

// Exists only to defeat instantiation.

}

public static SimpleSingleton getInstance() {

if (instance == null) {

instance = new SimpleSingleton();

}

return instance;

}

}

Take a look into the above class which is having a protected constructor and a public method getInstance().

There are several interesting points concerning the SimpleSingleton class. First, SimpleSingleton employs a technique known as lazy instantiation to create the singleton; as a result, the singleton instance is not created until the getInstance() method is called for the first time. This technique ensures that singleton instances are created only when needed.

Second, notice that SimpleSingleton implements a protected constructor so clients cannot instantiate SimpleSingleton instances; however, you may be surprised to discover that the following code is perfectly legal:

public class SimpleSingletontest extends TestCase {

public void testsing() {

SimpleSingleton instance = SimpleSingleton.getInstance();

SimpleSingleton anotherInstance = new SimpleSingleton();

Assert.assertEquals(true, instance == anotherInstance);

}

}

So, the first problem is lazy instantiation inorder to aviod that make few changes to SimpleSingleton...

public class SimpleSingleton {

private static SimpleSingleton instance = new SimpleSingleton();;

protected SimpleSingleton() {

// Exists only to defeat instantiation.

}

public static SimpleSingleton getInstance() {

return instance;

}

}

The second one is if we are declaring constructor as protected. There may be chanece of getting two objects. So we are violating the singleton pattern so make the constructor as private...

public class SimpleSingleton {

private static SimpleSingleton instance = new SimpleSingleton();;

private SimpleSingleton() {

// Exists only to defeat instantiation.

}

public static SimpleSingleton getInstance() {

return instance;

}

}

A third interesting point about SimpleSingleton , if SimpleSingleton implements the java.io.Serializable interface, the class's instances can be serialized and deserialized. However, if you serialize a singleton object and subsequently deserialize that object more than once, you will have multiple singleton instances

In order to avoid this the readResolve method should be implemented. See Serializable () and readResolve Method () in javadocs.

public class SimpleSingleton implements Serializable {
// This method is called immediately after an object of this class is deserialized.
// This method returns the singleton instance.
protected Object readResolve() {
return getInstance();
}
}

Note: The readResolve() method was added defaultly from java 1.5 (no need to write separately).

Finally, and perhaps most important, Example 1's SimpleSingleton class is not thread-safe. If two threads—we'll call them Thread 1 and Thread 2—call SimpleSingleton.getInstance() at the same time, two SimpleSingleton instances can be created if Thread 1 is preempted just after it enters the if block and control is subsequently given to Thread 2

public class Singleton {

private static Singleton singleton = null;

private static boolean firstThread = true;

protected Singleton() {

// Exists only to defeat instantiation.

}

public static Singleton getInstance() {

System.out.println(" time "+ System.currentTimeMillis());

if (singleton == null) {

simulateRandomActivity();

singleton = new Singleton();

}

System.out.println("created singleton: " + singleton);

return singleton;

}

private static void simulateRandomActivity() {

try {

if (firstThread) {

firstThread = false;

System.out.println("sleeping...");

// This nap should give the second threadenough time

// to get by the first thread.

Thread.currentThread().sleep(1000);

}

} catch (InterruptedException ex) {

System.out.println("Sleep interrupted");

}

}

}

Following is the test class to test Singleton

import junit.framework.Assert;

import junit.framework.TestCase;

public class SingletonTest extends TestCase {

private static Singleton singleton = null;

public SingletonTest(String name) {

super(name);

}

public void setUp() {

singleton = null;

}

public void testUnique() throws InterruptedException {

// Both threads call Singleton.getInstance().

Thread threadOne = new Thread(new SingletonTestRunnable()),

threadTwo = new Thread(new SingletonTestRunnable());

threadOne.start();

threadTwo.start();

threadOne.join();

threadTwo.join();

}

private static class SingletonTestRunnable implements Runnable {

public void run() {

System.out.println("Thread started");

// Get a reference to the singleton.

Singleton s = Singleton.getInstance();

// Protect singleton member variable from multithreaded access.

synchronized(SingletonTest.class) {

if(singleton == null) // If local reference is null...

singleton = s; // ...set it to the singleton

}

// Local reference must be equal to the one and only instance of Singleton; otherwise, we have two

// Singleton instances.

System.out.println("Thread finished");

Assert.assertEquals(true, s == singleton);

}

}

}

If u test this output is:

Thread started

time 1272456665200

sleeping...

Thread started

time 1272456665200

created singleton: Singletonwithmultythreading.Singleton@471e30

Thread finished

created singleton: Singletonwithmultythreading.Singleton@10ef90c

Thread finished

junit.framework.AssertionFailedError: expected: but was:

at junit.framework.Assert.fail(Assert.java:47)

at junit.framework.Assert.failNotEquals(Assert.java:282)

at junit.framework.Assert.assertEquals(Assert.java:64)

at junit.framework.Assert.assertEquals(Assert.java:149)

at junit.framework.Assert.assertEquals(Assert.java:155)

at Singletonwithmultythreading.SingletonTest$SingletonTestRunnable.run(SingletonTest.java:38)

at java.lang.Thread.run(Thread.java:534)

so inorder to avoid that add the synchronized to the getInstance() method. So that it will hold the first object once the first object lefts the method second object can cal that method.

package Singletonwithmultythreading;

public class Singleton {

private static Singleton singleton = null;

private static boolean firstThread = true;

protected Singleton() {

// Exists only to defeat instantiation.

}

public synchronized static Singleton getInstance() {

System.out.println(" time "+ System.currentTimeMillis());

if (singleton == null) {

simulateRandomActivity();

singleton = new Singleton();

}

System.out.println("created singleton: " + singleton);

return singleton;

}

private static void simulateRandomActivity() {

try {

if (firstThread) {

firstThread = false;

System.out.println("sleeping...");

// This nap should give the second thread enough time

// to get by the first thread.

Thread.currentThread().sleep(1000);

}

} catch (InterruptedException ex) {

System.out.println("Sleep interrupted");

}

}

}

Now if you test it will pass all with green lights by junit...

Output:-

Thread started

Thread started

time 1272457018077

sleeping...

created singleton: Singletonwithmultythreading.Singleton@471e30

time 1272457019077

created singleton: Singletonwithmultythreading.Singleton@471e30

Thread finished

Thread finished






http://www.javaworld.com/javaworld/jw-04-2003/jw-0425-designpatterns.html#resources

No comments:

Post a Comment