Monday, April 21, 2014

Writing singleton classes in Java

Singleton classes are those classes which can be instantiated only once. We need to restrict the creation of multiple instances of that class by blocking constructor access using new keyword etc, and instead regulate the incoming instance requests by creating the instance only once and return the same instance time and again on multiple calls.
Where do we actually need this singleton design pattern?

The answer will be where you need only one instance and not multiple instances of a class across your application. This does not degrades the performance since your work needs only single instance and using this design pattern you are preventing multiple instances. The actual case might just vary according to your needs. This may be logging, or database connection object. But you have to decide:
  • will you ever need exactly one instance in your application?
  • is your application expecting the exactly same implementation of this class?
among many other factors before you finally settle in to make a class singleton. An insightful reading at the developerWorks website can be found here.

There are many ways, some ways are presented here as different code snippets. Let me know if you have a better idea and see a flaw in these codes that I may have missed.

Code snippet 1:
package designpattern;
/**
 * Early instantiation means that the singleton instance 
 * is created during class loading itself and not when 
 * first used. So, no synchronization is required by using a static field.
 * This means that whether or not we require the singleton instance, 
 * it will be created and the object will be unique.
 * Works well in singlethreaded and multithreaded environments.
 * 
 * @author xploreraj
 */
class Singleton1 {
 private static Singleton1 instance = new Singleton1();
 
 private Singleton1() {
  //disable outside access
 }
 
 public static Singleton1 getInstance(){
  return instance;
 }
}


/*
 * test
 */
public class TestSingleton1 implements Runnable {
 
 public static void main(String[] args) {
  int count = 100;
  Thread thread[] = new Thread[count];
  for(int i=0; i< count; i++){
   thread[i] = new Thread(new TestSingleton1());
  }
  for(int j=0; j< count; j++){
   thread[j].start();
  }
  
 }

 @Override
 public void run() {
  Singleton1 instance = Singleton1.getInstance();
  System.out.println("Accessed by " + Thread.currentThread().getName() +
    "; Singleton1 instance is " + instance.hashCode());
  
 }
}

Code snippet 2:
package designpattern;
/**
 * Lazy instantiation of singleton using synchronization 
 * on getInstance() method makes it is usable in 
 * multithreaded environments.
 * 


 * The instance will be null only the first time, and 
 * then it will always be not null so that the singleton 
 * instance is returned directly. We need synchronization 
 * for the first time so that multiple threads 
 * concurrently do not get inside the getInstance() method 
 * while instance == null and then create multiple singleton instances.
 * But using synchronization on the method will unnecessarily 
 * take computation resources by locking the method everytime. 
 * Since instance is not null and getInstance() should return the instance directly.
 * 
 * @author xploreraj
 *
 */
class Singleton2 {
 private static Singleton2 instance;
 private Singleton2() {
  //hide from outside
 }

 public static synchronized Singleton2 getInstance() {

  if(instance==null) {
   for(int i=0; i< 100000; i++)
    ;

   instance = new Singleton2();
  }
  return instance;
 }//getInstance()
}

/*
 * test
 */
public class TestSingleton2 implements Runnable{

 public static void main(String[] args) {
  int count = 20;
  Thread thread[] = new Thread[count];
  for(int i=0; i< count; i++){
   thread[i] = new Thread(new TestSingleton2());
  }
  for(int j=0; j< count; j++){
   thread[j].start();
  }
  
 }//main()

 @Override
 public void run() {
  Singleton2 instance = Singleton2.getInstance();
  System.out.println("Accessed by " + Thread.currentThread().getName() +
    "; Singleton2 instance is " + instance.hashCode());
  
 }//run()

}

Code snippet 3:
package designpattern;
/**
 * clever but DEFECTIVE SINGLETON
 * Lazy instantiation of the singleton.
 * 

 * Checking the instance variable for null and then 
 * applying synchronization improves the code
 * at Singleton2 class, because if instance is 
 * not null, i.e., after first execution of the code,
 * the control will never get inside the synchronized 
 * block and computation cost will be saved. 

 * But there will be a problem. 
 * Say Thread1 checks instance = null and gets inside
 * the block but is preempted by Thread2 before executing 
 * the synchronized block. Now instance being null
 * Thread2 will also enter the block and for each of those 
 * threads, different instances will be created.
 * SO SINGLETON WILL NOT BE POSSIBLE IN MULTITHREADED ENVIRONMENT.
 * 
 * @author xploreraj
 *
 */
class Singleton3 {
 private static Singleton3 instance;
 private Singleton3() {
  //to do
 }
 
 public static Singleton3 getInstance() {
  if (instance==null){
   
   for(int j = 0; j< 100000;j++)
    //lets say that a thread is involved in something 
    //after coming inside this null checked block
    ;   
   
   synchronized(Singleton3.class){
     instance = new Singleton3();
   }
  }
  
  return instance;
 }
}

public class TestSingleton3 implements Runnable {

 public static void main(String[] args) {
  int count = 20;
  Thread thread[] = new Thread[count];
  for(int i=0; i< count; i++){
   thread[i] = new Thread(new TestSingleton3());
  }
  for(int j=0; j< count; j++){
   thread[j].start();
  }
  
 }//main()

 @Override
 public void run() {
  Singleton3 instance = Singleton3.getInstance();
  System.out.println("Accessed by " + Thread.currentThread().getName() +
    "; Singleton3 instance is " + instance.hashCode());
  
 }//run()

}

Code snippet 4:
package designpattern;
/**
 * Lazy instantiation of the singleton.
 * 

 * This is double-checked locking example and will prevent 
 * following scenario from breaking the singleton policy.

 * Description:

 * 1. Thread-1 enters getInstance() method for first time 
 * since instance == null, and then is preempted by Thread-2.

 * 2. Thread-2 enters getInstance() since instance is still null. 
 * It goes inside the inner synchronized block and 
 * once more instance == null check is done. It is null so 
 * instance has a new object now.

 * 3. Thread-2 is preempted by Thread-1, and now Thread-1 enters the 
 * internal synchronized block. Since an additional
 * check for instance == null is made, and this time 
 * instance is non-null, it will not reach the code for fresh
 * initialization.

 * Note:

 * There is a memory problem known as Out of Order writes in older JVM,
 * meaning a reference to an object could be returned by JVM just by
 * allocation memory and making the reference but before the construction,
 * precisely constructor logic, is actually over, so returning a partially
 * created object to one thread which cou,d lead to a lot of discrepancies.
 * Ref: http://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking--clever--but-broken.html
 * 
 * @author xploreraj
 *
 */
class Singleton4 {
 private static Singleton4 instance;
 private Singleton4() {
  //to do
 }
 
 public static Singleton4 getInstance() {
  if (instance==null){
   
   for(int j = 0; j< 100000;j++) 
    //lets say that a thread is involved in something 
    //after coming inside this null checked block
    ;
   
   synchronized(Singleton4.class){
    if (instance==null){
     instance = new Singleton4();
    }
   }
  } 
  return instance;
 }
}

public class TestSingleton4 implements Runnable {

 public static void main(String[] args) {
  int count = 20;
  Thread thread[] = new Thread[count];
  for(int i=0; i< count; i++){
   thread[i] = new Thread(new TestSingleton4());
  }
  for(int j=0; j< count; j++){
   thread[j].start();
  }
  
 }//main()

 @Override
 public void run() {
  Singleton4 instance = Singleton4.getInstance();
  System.out.println("Accessed by " + Thread.currentThread().getName() +
    "; Singleton4 instance is " + instance.hashCode());
  
 }//run()

}

Code snippet 5:
package designpattern;

/**
 * enums are by default singleton, inherently serializable, not clonable, with final fields
 * @author Rajdeep
 *
 */
enum EnumSingleton {
 INSTANCE;
 
 private EnumSingleton(){
  //can initialize something internally
 }
 
 public void doSomething(){
  //do something using same instance
 }
}

public class BestSingleton extends Thread{

 public static void main(String[] args) {
  int count = 100;
  Thread thread[] = new Thread[count];
  for(int i=0; i< count; i++){
   thread[i] = new Thread(new BestSingleton());
  }
  for(int j=0; j< count; j++){
   thread[j].start();
  }
  
 }//main()

 @Override
 public void run() {
  EnumSingleton instance = EnumSingleton.INSTANCE;
  System.out.println("Accessed by " + Thread.currentThread().getName() +
    "; EnumSingleton instance hashcode is " + instance.hashCode());
  
 }//run()

}

No comments:

Post a Comment

Liked or hated the post? Leave your words of wisdom! Thank you :)