Singleton Invalidated by Multithreading
Singleton will work properly in multithreaded environment only if eager instantiation has been done because in this case instance creation will happen at the time of class loading only. But for Lazy instantiation we will have to take care of multiple things. If we want to delay the instantiation because of cost, we use to go with lazy.
Example
package com.loopandbreak.singleton; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SingletonInvalidatedByMultithreading { private static SingletonInvalidatedByMultithreading singletonObject = null; private SingletonInvalidatedByMultithreading() { System.out.println("Creating Object."); } public static SingletonInvalidatedByMultithreading getInstance() { if (singletonObject == null) { singletonObject = new SingletonInvalidatedByMultithreading(); } return singletonObject; } static void useSingleton() { SingletonInvalidatedByMultithreading obj = SingletonInvalidatedByMultithreading.getInstance(); print(obj); } public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.submit(SingletonInvalidatedByMultithreading::useSingleton); executorService.submit(SingletonInvalidatedByMultithreading::useSingleton); } private static void print(SingletonInvalidatedByMultithreading obj) { System.out.println("Hashcode of object is " + obj.hashCode()); } }
When you run the above program many times you will notice that in multithreaded environment sometimes Singleton principle works but sometimes it violates.
Output
Creating Object. Hashcode of object is 974798335 Creating Object. Hashcode of object is 645970594
We are applying double check locking here and keeping the instance as volatile so that one state shared between multiple threads.
Example
package com.loopandbreak.singleton; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SingletonInvalidatedByMultithreading { private static volatile SingletonInvalidatedByMultithreading singletonObject = null; private SingletonInvalidatedByMultithreading() { System.out.println("Creating Object."); } public static SingletonInvalidatedByMultithreading getInstance() { if (singletonObject == null) { synchronized (SingletonInvalidatedByMultithreading.class) { if (singletonObject == null) { singletonObject = new SingletonInvalidatedByMultithreading(); } } } return singletonObject; } static void useSingleton() { SingletonInvalidatedByMultithreading obj = SingletonInvalidatedByMultithreading.getInstance(); print(obj); } public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.submit(SingletonInvalidatedByMultithreading::useSingleton); executorService.submit(SingletonInvalidatedByMultithreading::useSingleton); } private static void print(SingletonInvalidatedByMultithreading obj) { System.out.println("Hashcode of object is " + obj.hashCode()); } }
Output
Creating Object. Hashcode of object is 290209249 Hashcode of object is 290209249
Now, irrespective of how many times you execute this program, you’ll get same single instance for multiple threads.