Sunday, 17 April 2016

What problems may occur when using Singleton pattern in multithreaded environment ?



Suppose, in our project, we are loading an XML file in the constructor of the Singleton class.
It appeared to be very simple but we faced an unexpected exception.

We write a brief code based on common singleton :
class DateCounterInfoFile {
  private static DateCounterInfoFile dateCounterInfoFile;
  private DateCounterInfoFile()  {
    this.loadDateCounterMap(_fileName); //loading xml in constructor
  }
  public static DateCounterInfoFile getInstance()  {
    if (dateCounterInfoFile == null)
      dateCounterInfoFile = new DateCounterInfoFile();
    return dateCounterInfoFile;
  }
}


Problem 1

Only one object of DateCounterInfoFile class is created.
The above implementation works fine in a single-threaded environment.

Solution
In case of multiple threads, we must protect the method getInstance() by using synchronization.
// Singleton in Multithreaded environment
class DateCounterInfoFile {
  private static DateCounterInfoFile dateCounterInfoFile;
  private DateCounterInfoFile()  {
    this.loadDateCounterMap(_fileName); // loads an xml file
  }
  public static Singleton getInstance()  {
    if (dateCounterInfoFile == null)       {    // 1
      synchronized(DateCounterInfoFile.class) {      // 2
        if (dateCounterInfoFile == null)                  // 3
           dateCounterInfoFile = new DateCounterInfoFile();  // 4
      }
    }
    return dateCounterInfoFile;
  }
}


Problem 2

Inside the private constructor of DateCounterInfoFile class, we have called a function, which loads the xml file.

Flow of threads is :
1. Thread 1 enters line 1 and checks that instance of DateCounterInfoFile is null.
2. It enters synchronized block at line 2 and makes instance not null at line 4.
3. Thread 1 is preempted by Thread 2 after memory is allocated to DateCounterInfoFile object but before it is initialized (we’ll get back to this after a short while).
4. Now Thread 2 enters line 1 and finds that DateCounterInfoFile object is not null and returns partially initialized object.
5. Now Thread 2 is preempted by Thread 1again and Thread 1 completes initialization of DateCounterInfoFileobject and returns fully initialized object.
6. Thus, we are left with 2 objects of our class, among which one is partially constructed and other is fully constructed.

Let’s see, what happens when ‘dateCounterInfoFile = new dateCounterInfoFile()’ compiles :
It is broken down into three simple steps :
1. mem = allocate (memory is allocated for the object)
2. dateCounterInfoFile = mem (Thus, dateCounterInfoFile becomes not null but it is not initialized)
3. constructor is invoked.

Thus, going back to point 3 we findThread 2 preempt Thread 1 just before constructor is invoked and just after memory is allocated !

So, when we tried to run our code, it gave unpredictable results. Some times it used to run properly while sometimes, it threw ‘NullPointerException’ at us as the constructor didn't execute fully which left us with no xml file loaded (Note - we were trying to load our XML file inside the constructor)

Solution
To avoid this problem, we use Volatile keyword. It ensures that volatile read must happen after the write has taken place.
Thus in this way, reading thread will always see the correct value of variable dateCounterInfoFile.
class DateCounterInfoFile {
   private static volatile DateCounterInfoFile dateCounterInfoFile;
   // Rest of the code remains the same as above.
}


Problem 3

When variables are declared volatile, they are reconciled with main memory on every access.
On the other hand, when synchronization is used, the variables are reconciled with main memory only when lock is obtained and lock is released.
Thus, using volatile might be slower than synchronization.

Solution
To overcome this problem, use the advantage of Bill Pugh solution.
The solution is thread safe and does not uses either ‘volatile’ or‘synchronization’.
class DateCounterInfoFile {
  private static DateCounterInfoFile dateCounterInfoFile;
  private DateCounterInfoFile() {
    this.loadDateCounterMap(_fileName); // loads an XML file
  }
  private static class SingletonHolder {
    private final static DateCounterInfoFile dateCounterInfoFile =  
                           new DateCounterInfoFile();
  }
  public static DateCounterInfoFile getInstance() {
    return SingletonHolder.dateCounterInfoFile;
  }
}

SingletonHolder is loaded on the first execution of getInstance() method.
This technique is also known as ‘lazy Initialization’ or ‘Initialization on demand’.

No comments:

Post a Comment

Note: only a member of this blog may post a comment.