The Singleton pattern can make your life easier

When there is a lot of code, there can be a lot of complexity too.  It is quite often a scenario that different parts of an app need access to the same object.  That object, for examples, could be a counter generating serial numbers, a database accessor, or other types that must be instantiated only once.  In the case of a counter, the program must increment the serial numbers in a consistent way; there cannot be more than one counters to provide serial numbers.  In the case of a database accessor, the program must always access to the same set of data.

The different parts of the app could be running concurrently, and we want to avoid having too many the objects created by error.  Sometimes codes may not be written very carefully and mistakes can happen.  If we want to ensure that there is always only one instance of such an object, and to have the different parts of the app easily call to it, the Singleton pattern technique can help.

Let's say there is a class called MyClass that we want to ensure there is only one instance of it.

// Always want one instance only
class MyClass {    
    private String text;    
    public MyClass (String text) {
        this.text = text;
    }    
    public String getText() {
        return this.text;
    }    
}

For one thread at a time accessing the myClass object...

Instead of using the regular declaration to instantiate MyClass, for example,  MyClass myClass = new MyClass("Hello"), we can create a helper class to create the object.  That helper class will ensure there is only one instance has been created.  Here is an example of helper class called MySingleton.

class MySingleton {
    private static MyClass myClass;        
    public static MyClass getInstance (String text) {        
        if (myClass == null) 
            myClass = new MyClass(text);                       
        return myClass;        
    }
}

When different parts of the application need access to the MyClass object, we can code in the way that always call to the only public static method called getInstance, like below:

MyClass myClass = MySingleton.getInstance("Hello");

If the object myClass is not already there, the getInstance method will create it and return it.  Otherwise, the getInstance method will simply return it.

For multiple threads at a time accessing the myClass object...

When there are multiple threads trying to call getInstance, there are two issues need to be addressed in the MySingleton class above.  Scenario 1: Imagine that when two threads are calling getInstance at the same time before MyClass gets instantiated, they will both see myClass == null.  In this case, MyClass will get instantiated by both threads thus defeating the purpose of Singleton.   Scenario 2: Imagine that right after the first thread has called to getInstance to instantiate MyClass, almost instantly the second thread also calls to getInstance.  At that time, MyClass has already been instantiated by the first thread.  Whether the second thread can see that or not depends on the chance of checking which part of cache memory or real memory.  The above code does not guarantee the second thread is able to see myClass no longer null.

To address the issue of Scenario 1, we can apply the synchronized modifier, and for Scenario 2, the volatile modifier, as shown below.

class MySingleton {   
    private static volatile MyClass myClass;            
    public static MyClass getInstance (String text) {            
        if (myClass == null) {            
            synchronized (MyClass.class) {                    
                if (myClass == null)
                    myClass = new MyClass(text);                       
            }            
        }
        return myClass;        
    }
}

The synchronized modifier indicates that the code within the braces can only be accessed by one thread at a time.  By doing so, we can avoid Scenario 1 that two threads instantiating MyClass at the same time.  Notice that the condition checking if (myClass==null) seems duplicated but that serves a purpose.  If the first check is true, then perform the synchronized operation; otherwise, that expensive operation is not necessary since the only instance of myClass can be returned to one or more threads.  The second check is synchronized, guaranteeing only one thread can instantiate MyClass.  The double-checking of the same condition -- with one is not synchronized while the other one is, is known as Double-checked Locking optimization.  It reduces the overhead of acquiring a lock by testing the locking criterion before acquiring the lock.

The volatile modifier indicates that the object myClass will need to be written in real memory instead of somewhere in level 1 cache, level 2 cache, or real memory etc.   Ensuring myClass to be written in real memory is a more expansive operation than letting the system decide which part of memory to write.  Also the subsequent read/write to myClass will be required accessing real memory every time.  This more expansive operation will guarantee the myClass object visible to multiple threads.

Having said that, if we know that getInstance will only be called by one thread at a time, it will be more efficient to have MySingleton without using the volatile and synchronized modifiers.


Comments

Popular posts from this blog

Finding Median by Stream

Factorial by Different Styles in Java

Reduction by Java Stream