From ea6c4e5a8aa3e7b344c1bd424e9ed2f63ef94805 Mon Sep 17 00:00:00 2001 From: Abhijay Kumar Date: Tue, 14 May 2019 14:54:50 +0530 Subject: [PATCH] Added Singleton Design pattern implementation in Java and its test --- .../singletonpattern/Singleton.java | 44 ++++++++++++++++++ .../singletonpattern/SingletonTest.java | 45 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 src/main/java/com/designpatterns/singletonpattern/Singleton.java create mode 100644 src/test/java/com/designpatterns/singletonpattern/SingletonTest.java diff --git a/src/main/java/com/designpatterns/singletonpattern/Singleton.java b/src/main/java/com/designpatterns/singletonpattern/Singleton.java new file mode 100644 index 00000000..f846c33b --- /dev/null +++ b/src/main/java/com/designpatterns/singletonpattern/Singleton.java @@ -0,0 +1,44 @@ +package src.main.java.com.designpatterns.singletonpattern; + +/** + * The singleton pattern is a design pattern that restricts the instantiation of a class to one "single" instance. + * This is useful when exactly one object is needed to coordinate actions across the system. The term comes from the + * mathematical concept of a singleton. + *

+ * The key idea in this pattern is to make the class itself responsible for controlling its instantiation (only once). + * The hidden constructor (declared private) ensures that the class can never be instantiated from outside the class. + * The public static operation can be accessed easily by using the class name and function name(Singleton.getInstance()) + * + * @see Singleton Pattern + */ +public class Singleton { + private volatile static Singleton instance = null; + + private Singleton() { + } + + /** + * A singleton implementation may use lazy initialization, where the instance is created when the static method + * is first invoked. + *

+ * If the static method might be called from multiple threads simultaneously, measures may need + * to be taken to prevent race conditions that could result in the creation of multiple instances of the class. + *

+ * The following implementation is a thread-safe sample implementation, using lazy initialization with + * double-checked locking. + * + * @return the single instance of the Singleton class + */ + public static Singleton getInstance() { + if (instance == null) { + // First attempt to make thread safe + synchronized (Singleton.class) { + // Double Checked locking as multiple threads can reach the above step + if (instance == null) { + instance = new Singleton(); + } + } + } + return instance; + } +} diff --git a/src/test/java/com/designpatterns/singletonpattern/SingletonTest.java b/src/test/java/com/designpatterns/singletonpattern/SingletonTest.java new file mode 100644 index 00000000..2b7058ea --- /dev/null +++ b/src/test/java/com/designpatterns/singletonpattern/SingletonTest.java @@ -0,0 +1,45 @@ +package src.test.java.com.designpatterns.singletonpattern; + +import org.junit.Assert; +import org.junit.Test; +import src.main.java.com.designpatterns.singletonpattern.Singleton; + +import java.util.ArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class SingletonTest { + private static volatile ArrayList hashCodeList = new ArrayList<>(); + + @Test + public void testSingleton() throws InterruptedException { + boolean testFailed = false; + ExecutorService es = Executors.newCachedThreadPool(); + // Creates 15 threads and makes all of them access the Singleton class + // Saves the hash code of the object in a static list + for (int i = 0; i < 15; i++) + es.execute(() -> { + try { + Singleton singletonInstance = Singleton.getInstance(); + int singletonInsCode = singletonInstance.hashCode(); + System.out.println(singletonInsCode); + hashCodeList.add(singletonInsCode); + } catch (Exception e) { + System.out.println("Exception is caught"); + } + }); + es.shutdown(); + boolean finished = es.awaitTermination(1, TimeUnit.MINUTES); + // wait for all threads to finish + if (finished) { + Integer firstCode = hashCodeList.get(0); + for (Integer code : hashCodeList) { + if (!firstCode.equals(code)) { + testFailed = true; + } + } + Assert.assertFalse(testFailed); + } + } +}