Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/main/java/com/designpatterns/singletonpattern/Singleton.java
Original file line number Diff line number Diff line change
@@ -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.
* <p>
* 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 <a href="https://en.wikipedia.org/wiki/Singleton_pattern">Singleton Pattern</a>
*/
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.
* <p>
* 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.
* <p>
* 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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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<Integer> 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();
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);
}
}
}