Saturday 27 May 2017

Design Pattern Interview Questions - I

1. What is Singleton design pattern in Java? 

Answer: Singleton design pattern comes under the category of creational design pattern. In software engineering creational design pattern is about how we create objects.
Singleton design pattern ensures that there is only one object exist for a class in Java Virtual Machine. All request for object of class will get served with same single object.
Also In this pattern singleton class provides the global point of access (factory method) in order to use singleton object.
Example:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Singleton {
 private static Singleton mySingleton;

 private Singleton(){
 }

 static Singleton getMySingleton() {
  if(null == mySingleton){
   mySingleton = new Singleton();
  }
  return mySingleton;
 }
}
Test Class:
1
2
3
4
5
6
public class SingletonTest {
 public static void main(String[] args) {
  System.out.println("HashCode of first Object  :: " + Singleton.getMySingleton().hashCode());
  System.out.println("HashCode of second Object :: " + Singleton.getMySingleton().hashCode());
 }
}
Let's discuss code of Singleton class:
1. Factory method getMySingleton(): It is global point to access singleton object. Code is very simple, We are checking if object is null then create new object else return already created object.
So for the first request value of mySingelton will be null hence Java will create new object of Singleton class and will return the same. Now for any subsequent request since Java has already created object for you hence value of mySingelton won't be null hence it will return same singleton object created on first request.

Note: In code we have getMySingleton() method as static so we can access the method without any object just by using class name.

2. Static instance variable of type Singleton: We have static member variable mySingleton of type Singleton. 
Since getMySingleton() is a static method and we can not access non static variables from static methods hence in order to access mySingleton variable from static method we have kept it as static.

2. What is the limitation of above mentioned implementation of singleton pattern?

AnswerThe implementation we have above is basic version of singleton pattern and this code will work fine in single threaded environment without any changes.
But if we use same code for multi threaded environment then this code won't work.

Limitation of above code in multi threaded environment : Assume Thread-1 get inside getMySingelton() method, It then checks whether or not mySingelton is null assume It's first request so value of mySingelton will be null hence Thread-1 will get inside if block. 
Now assume as soon as Thread-1 get inside if block it lost the CPU and now Thread-2 got chance of execution. Since Thread-1 did not create the object yet hence for Thread-2 value of mySingleton will be null. Hence Thread-2 will also get inside and will create the object and return from method successfully. 
Now After Thread-2 completed it's execution Thread-1 got chance again to continue it's execution from same point. Since Thread-1 is already inside if block which means Thread-1 has no way to check whether or not object(mySingelton) is null hence it will also create the object and then return successfully. So we will end up with two object created by Thread-1 and Thread-2. 
So we can conclude that above implementation is absolutely fine for single threaded environment but since it is not thread-safe hence required some modification to work well in multi-threaded environment.

3. Write the thread-safe version of singleton pattern?
Answer Synchronization is the solution to write thread-safe code.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Singleton {
 private static Singleton mySingleton;

 private Singleton(){
 }

 static synchronized Singleton getMySingleton() {
  if(null == mySingleton){
   mySingleton = new Singleton();
  }
  return mySingleton;
 }
}
In this implementation we have synchronized the getMySingelton() method, which solves  the problem of thread safety. 
Now only one thread can access the getMySingelton() method at a time. if Thread-1 is already inside the method then Thread-2 and all other threads has to wait for Thread-1 to complete it's execution.
We can improve the code further by using synchronized block instead of synchronizing whole method. Block level synchronization gives better performance as we are not blocking entire method.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Singleton {
 private static Singleton mySingleton;

 private Singleton(){
 }

 static  Singleton getMySingleton() {
  synchronized(Singleton.class){
   if(null == mySingleton){
   mySingleton = new Singleton();
   }
  }
  return mySingleton;
 }
}

4. What is double check locking?
AnswerThe double check locking is a way to improvise the thread safe version of singleton code (as we have single check for null in above code). In below code we have double check for null, first at line number 9 without lock and second at line number 11 with lock. This is reason we call it double check locking. 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Singleton {
 private static Singleton mySingleton;

 private Singleton() {

 }

 static Singleton getMySingleton() {
  if (null == mySingleton) {    //First check 
   synchronized (Singleton.class) {
    if (null == mySingleton) {  //Second check
     mySingleton = new Singleton();
    }
   }
  }
  return mySingleton;
 }
}
How double check locking is better than single check : In case of single check thread first takes the lock and then checks for null, so in the case if the object was not null then there was no point of taking lock in first place.
But in double check locking thread first checks for null if it's not null then only thread takes the lock otherwise thread doesn't take the lock and returns the object directly.

5. Is double check locking is completely thread safe? 

AnswerAnswer is NO, double check locking doesn't provide complete thread safety, It is sill broken. It looks like it will work fine and even in most of cases it will work fine.
But sill there are possibilities where it can fail because of re-ordering of instructions.

Solution : Volatile variable, To make it complete thread safe we need to use the concept of volatile. As in case of volatile variables Java doesn't allow compiler to re-order the instructions.

Volatile keyword guarantees that if one thread is performing write operation on a variable then no other thread can read the value of that variable till the write operation is going on. The read operation will happen after the completion of on going write operation in order to maintain consistency.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Singleton {
 private static volatile Singleton mySingleton;

 private Singleton() {

 }

 static Singleton getMySingleton() {
  if (null == mySingleton) {     //First check 
   synchronized (Singleton.class) {
    if (null == mySingleton) {   //Second check
     mySingleton = new Singleton();
    }
   }
  }
  return mySingleton;
 }
}
Above code is final version of a thread safe singleton class which will work fine in all scenario.

6. Singleton design pattern and serialization?

AnswerSingleton design pattern doesn't work as it should work if our singleton class implements serializable interface. If you the run below code you will get different hash codes printed at console, which clearly suggests that after deserialization we got a new object instead of same object that we have. 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package design.pattern.creational;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Singelton {
 public static void main(String[] args) {
  Singleton mySingleton1 = Singleton.getMySingleton();
  
  //****Serialization : Start*****//*
  try {
   ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(new File("test.ser")));
   objectOutputStream.writeObject(mySingleton1); 
  } catch (IOException e) {
   e.printStackTrace();
  }
  //****Serialization : End*****//*
  
  /***Deserialization : Start*****/
  Singleton mySingleton2 = null;
  try {
   ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("test.ser")));
   mySingleton2 =  (Singleton)objectInputStream.readObject();
  }catch (IOException | ClassNotFoundException e) {
   e.printStackTrace();
  }
  /*****Deserialization : End*****/ 
  
  System.out.println("HashCode of first Object  :: "+mySingleton1.hashCode());
  System.out.println("HashCode of second Object :: "+mySingleton2.hashCode());
 }
}

class Singleton implements Serializable{
 private static volatile Singleton mySingleton;

 private Singleton() {

 }

 static Singleton getMySingleton() {
  if (null == mySingleton) {     //First check 
   synchronized (Singleton.class) {
    if (null == mySingleton) {   //Second check
     mySingleton = new Singleton();
    }
   }
  }
  return mySingleton;
 }
}

Solution: To Solve above problem we need to override readResolve method as below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Singleton implements Serializable{
 private static volatile Singleton mySingleton;

 private Singleton() {

 }

 static Singleton getMySingleton() {
  if (null == mySingleton) {     //First check 
   synchronized (Singleton.class) {
    if (null == mySingleton) {   //Second check
     mySingleton = new Singleton();
    }
   }
  }
  return mySingleton;
 }
 
 public Object readResolve(){
  return getMySingleton();  
 }
}

7. Singleton class using Enum?

Answer Enum is best way of writing singleton class which works absolutely fine in all the scenario discussed above. It works absolutely fine in multi threaded environment without any changes in below code.
1
2
3
enum Singleton{
 INSTANCE;
}

Also read Design Pattern Interview Questions - II.

No comments:

Post a Comment