How to make Singleton object- Thread access two singleton object

One point which is worth remembering is that, when we talk about thread-safe Singleton, we are talking about thread-safety during instance creation of Singleton class and not when we call any method of Singleton class. If your Singleton class maintain any state and contains method to modify that state, you need to write code to avoid and thread-safety and synchronization issues.

Example 1

Following implementation shows a Singleton design pattern. Singleton class 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.

public class Singleton {
   private static Singleton _instance = null;
    
   private Singleton() {}
    
   public static Singleton getInstance() {
       if (_instance == null) {
           _instance = new Singleton();
       }
       return _instance;
   }
}

But we have a slight problem with this. This classical implementation is not thread safe. Lets see what may happen in the presence of two threads.

a. Thread-1 enters getInstance() for the first time and sees that _instance is null and thus the condition is true.
b. Before instantiating the object a thread switch occur.
c. Thread-2 enters getInstance() and it will see _instance null too, as the instantiation by Thread-1 is not completed yet.
d. Thread-2 instantiate new object and then return.
e. Thread-1 knows nothing about Thread-2. So when it gets its turn again, it instantiates another object and returns that. At this point we have two instances of f. Singleton which violates the fundamental purpose of the pattern.
Example 2

The easiest solution comes up if we don’t want the lazy initialization. Something like this:
public class Singleton {
   private static Singleton singleton = new Singleton( );
   /* A private Constructor prevents any other
    * class from instantiating.
    */
   private Singleton() { }

   /* Static 'instance' method */
   public static Singleton getInstance( ) {
      return singleton;
   }

   /* Other methods protected by singleton-ness */
   protected static void demoMethod( ) {
      System.out.println("demoMethod for singleton");
   }
}

This is guaranteed to be thread safe. The only cost that we pay is that we lose the lazy initialization. 

But what if we want the lazy initialization?  The general approach to write a thread safe code is to acquire a lock before accessing the shared resource. We can acquire a thread lock after entering getInstance(). Something like this:
public static Singleton getInstance() {
    acquire_lock();
    if (_instance == null) {
        _instance = new Singleton();
    }
    release_lock();
        
    return _instance;
}


Acquiring a lock at every call of getInstance() may affect the overall performance severely, especially when the calls are frequent. And to make matter worse, we only need the lock for the first time. Once _instance is set up with a valid value, there is no need of the locking. But we are acquiring the lock every time and thus wasting our resource. The very idea of lazy initialization is to use resource efficiently.
We have already realized that the lock is only needed for the first time. There is no need to acquire lock once _instance is initialized. So why don’t we acquire the lock only if _instance is null, like this:
public static Singleton getInstance() {
    if (_instance == null) {
        acquire_lock();
        _instance = new Singleton();
        release_lock();
    }
    return _instance;
}

Thread-1 may see the condition true and enter the condition, but before acquiring the lock thread switch may occur. Then Thread-2 will again find the condition true and thus we are in the same situation as before.
We only need to check _instance against null again after acquiring the lock. Like this:
public static Singleton getInstance() {
    if (_instance == null) {
        acquire_lock();
        if (_instance == null) {
            _instance = new Singleton();
        }
        release_lock();
    }
             
    return _instance;
}

Lets see what happens with the previous situation:

Thread-1 enters the condition but before acquiring the lock thread switch occurs.
Thread-2 enters the condition, acquires lock, instantiates, releases lock and returns like before.
Thread-1 acquires the lock. But now it will see that _instance is non-null and thus it will not create a new object. It will simply release the lock and return the object created by Thread-2.
Looks like our problem with multiple threads is finally finished.

Comments

Popular posts from this blog

Install Alfresco Content Service 6.0 on ubuntu 16 using distribution zip

Lucene and fts-search

Call javascript webscript from contoller