Reformat rest of the design patterns - Issue #224
This commit is contained in:
@ -1,35 +1,40 @@
|
||||
package com.iluwatar.singleton;
|
||||
|
||||
/**
|
||||
* Singleton pattern ensures that the class can have only one existing instance per Java classloader instance
|
||||
* and provides global access to it.
|
||||
* Singleton pattern ensures that the class can have only one existing instance per Java classloader
|
||||
* instance and provides global access to it.
|
||||
* <p/>
|
||||
* One of the risks of this pattern is that bugs resulting from setting a singleton up in
|
||||
* a distributed environment can be tricky to debug, since it will work fine if you
|
||||
* debug with a single classloader. Additionally, these problems can crop up a while
|
||||
* after the implementation of a singleton, since they may start out synchronous and
|
||||
* only become async with time, so you it may not be clear why you are seeing certain
|
||||
* changes in behaviour.
|
||||
* One of the risks of this pattern is that bugs resulting from setting a singleton up in a
|
||||
* distributed environment can be tricky to debug, since it will work fine if you debug with a
|
||||
* single classloader. Additionally, these problems can crop up a while after the implementation of
|
||||
* a singleton, since they may start out synchronous and only become async with time, so you it may
|
||||
* not be clear why you are seeing certain changes in behaviour.
|
||||
* <p/>
|
||||
* There are many ways to implement the Singleton. The first one is the eagerly initialized instance in
|
||||
* {@link IvoryTower}. Eager initialization implies that the implementation is thread safe. If you can
|
||||
* afford giving up control of the instantiation moment, then this implementation will suit you fine.
|
||||
* There are many ways to implement the Singleton. The first one is the eagerly initialized instance
|
||||
* in {@link IvoryTower}. Eager initialization implies that the implementation is thread safe. If
|
||||
* you can afford giving up control of the instantiation moment, then this implementation will suit
|
||||
* you fine.
|
||||
* <p/>
|
||||
* The other option to implement eagerly initialized Singleton is enum based Singleton. The example is
|
||||
* found in {@link EnumIvoryTower}. At first glance the code looks short and simple. However, you should
|
||||
* be aware of the downsides including committing to implementation strategy, extending the enum class,
|
||||
* serializability and restrictions to coding. These are extensively discussed in Stack Overflow:
|
||||
* http://programmers.stackexchange.com/questions/179386/what-are-the-downsides-of-implementing-a-singleton-with-javas-enum
|
||||
* The other option to implement eagerly initialized Singleton is enum based Singleton. The example
|
||||
* is found in {@link EnumIvoryTower}. At first glance the code looks short and simple. However, you
|
||||
* should be aware of the downsides including committing to implementation strategy, extending the
|
||||
* enum class, serializability and restrictions to coding. These are extensively discussed in Stack
|
||||
* Overflow:
|
||||
* http://programmers.stackexchange.com/questions/179386/what-are-the-downsides-of-implementing
|
||||
* -a-singleton-with-javas-enum
|
||||
* <p/>
|
||||
* {@link ThreadSafeLazyLoadedIvoryTower} is a Singleton implementation that is initialized on demand.
|
||||
* The downside is that it is very slow to access since the whole access method is synchronized.
|
||||
* {@link ThreadSafeLazyLoadedIvoryTower} is a Singleton implementation that is initialized on
|
||||
* demand. The downside is that it is very slow to access since the whole access method is
|
||||
* synchronized.
|
||||
* <p/>
|
||||
* Another Singleton implementation that is initialized on demand is found in {@link ThreadSafeDoubleCheckLocking}. It
|
||||
* is somewhat faster than {@link ThreadSafeLazyLoadedIvoryTower} since it doesn't synchronize the whole access method
|
||||
* but only the method internals on specific conditions.
|
||||
* Another Singleton implementation that is initialized on demand is found in
|
||||
* {@link ThreadSafeDoubleCheckLocking}. It is somewhat faster than
|
||||
* {@link ThreadSafeLazyLoadedIvoryTower} since it doesn't synchronize the whole access method but
|
||||
* only the method internals on specific conditions.
|
||||
* <p/>
|
||||
* Yet another way to implement thread safe lazily initialized Singleton can be found in {@link InitializingOnDemandHolderIdiom}.
|
||||
* However, this implementation requires at least Java 8 API level to work.
|
||||
* Yet another way to implement thread safe lazily initialized Singleton can be found in
|
||||
* {@link InitializingOnDemandHolderIdiom}. However, this implementation requires at least Java 8
|
||||
* API level to work.
|
||||
*/
|
||||
public class App {
|
||||
|
||||
@ -47,10 +52,10 @@ public class App {
|
||||
System.out.println("ivoryTower2=" + ivoryTower2);
|
||||
|
||||
// lazily initialized singleton
|
||||
ThreadSafeLazyLoadedIvoryTower threadSafeIvoryTower1 = ThreadSafeLazyLoadedIvoryTower
|
||||
.getInstance();
|
||||
ThreadSafeLazyLoadedIvoryTower threadSafeIvoryTower2 = ThreadSafeLazyLoadedIvoryTower
|
||||
.getInstance();
|
||||
ThreadSafeLazyLoadedIvoryTower threadSafeIvoryTower1 =
|
||||
ThreadSafeLazyLoadedIvoryTower.getInstance();
|
||||
ThreadSafeLazyLoadedIvoryTower threadSafeIvoryTower2 =
|
||||
ThreadSafeLazyLoadedIvoryTower.getInstance();
|
||||
System.out.println("threadSafeIvoryTower1=" + threadSafeIvoryTower1);
|
||||
System.out.println("threadSafeIvoryTower2=" + threadSafeIvoryTower2);
|
||||
|
||||
@ -65,13 +70,13 @@ public class App {
|
||||
System.out.println(dcl1);
|
||||
ThreadSafeDoubleCheckLocking dcl2 = ThreadSafeDoubleCheckLocking.getInstance();
|
||||
System.out.println(dcl2);
|
||||
|
||||
|
||||
// initialize on demand holder idiom
|
||||
InitializingOnDemandHolderIdiom demandHolderIdiom =
|
||||
InitializingOnDemandHolderIdiom.getInstance();
|
||||
InitializingOnDemandHolderIdiom.getInstance();
|
||||
System.out.println(demandHolderIdiom);
|
||||
InitializingOnDemandHolderIdiom demandHolderIdiom2 =
|
||||
InitializingOnDemandHolderIdiom.getInstance();
|
||||
InitializingOnDemandHolderIdiom.getInstance();
|
||||
System.out.println(demandHolderIdiom2);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
package com.iluwatar.singleton;
|
||||
|
||||
/**
|
||||
* Enum based singleton implementation.
|
||||
* Effective Java 2nd Edition (Joshua Bloch) p. 18
|
||||
* Enum based singleton implementation. Effective Java 2nd Edition (Joshua Bloch) p. 18
|
||||
*/
|
||||
public enum EnumIvoryTower {
|
||||
|
||||
|
@ -3,13 +3,12 @@ package com.iluwatar.singleton;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* The Initialize-on-demand-holder idiom is a secure way of
|
||||
* creating lazy initialized singleton object in Java.
|
||||
* refer to "The CERT Oracle Secure Coding Standard for Java"
|
||||
* By Dhruv Mohindra, Robert C. Seacord p.378
|
||||
* The Initialize-on-demand-holder idiom is a secure way of creating lazy initialized singleton
|
||||
* object in Java. refer to "The CERT Oracle Secure Coding Standard for Java" By Dhruv Mohindra,
|
||||
* Robert C. Seacord p.378
|
||||
* <p/>
|
||||
* Singleton objects usually are heavy to create and sometimes need to serialize them.
|
||||
* This class also shows how to preserve singleton in serialized version of singleton.
|
||||
* Singleton objects usually are heavy to create and sometimes need to serialize them. This class
|
||||
* also shows how to preserve singleton in serialized version of singleton.
|
||||
*
|
||||
* @author mortezaadi@gmail.com
|
||||
*/
|
||||
@ -17,8 +16,7 @@ public class InitializingOnDemandHolderIdiom implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private InitializingOnDemandHolderIdiom() {
|
||||
}
|
||||
private InitializingOnDemandHolderIdiom() {}
|
||||
|
||||
public static InitializingOnDemandHolderIdiom getInstance() {
|
||||
return HelperHolder.INSTANCE;
|
||||
@ -30,7 +28,7 @@ public class InitializingOnDemandHolderIdiom implements Serializable {
|
||||
|
||||
private static class HelperHolder {
|
||||
public static final InitializingOnDemandHolderIdiom INSTANCE =
|
||||
new InitializingOnDemandHolderIdiom();
|
||||
new InitializingOnDemandHolderIdiom();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
package com.iluwatar.singleton;
|
||||
|
||||
/**
|
||||
* Singleton class.
|
||||
* Eagerly initialized static instance guarantees thread
|
||||
* safety.
|
||||
* Singleton class. Eagerly initialized static instance guarantees thread safety.
|
||||
*/
|
||||
public final class IvoryTower {
|
||||
|
||||
@ -15,12 +13,10 @@ public final class IvoryTower {
|
||||
/**
|
||||
* Private constructor so nobody can instantiate the class.
|
||||
*/
|
||||
private IvoryTower() {
|
||||
}
|
||||
private IvoryTower() {}
|
||||
|
||||
/**
|
||||
* To be called by user to
|
||||
* obtain instance of the class.
|
||||
* To be called by user to obtain instance of the class.
|
||||
*
|
||||
* @return instance of the singleton.
|
||||
*/
|
||||
|
@ -17,7 +17,7 @@ public class ThreadSafeDoubleCheckLocking {
|
||||
* private constructor to prevent client from instantiating.
|
||||
*/
|
||||
private ThreadSafeDoubleCheckLocking() {
|
||||
//to prevent instantiating by Reflection call
|
||||
// to prevent instantiating by Reflection call
|
||||
if (INSTANCE != null) {
|
||||
throw new IllegalStateException("Already initialized.");
|
||||
}
|
||||
@ -29,8 +29,8 @@ public class ThreadSafeDoubleCheckLocking {
|
||||
* @return an instance of the class.
|
||||
*/
|
||||
public static ThreadSafeDoubleCheckLocking getInstance() {
|
||||
//local variable increases performance by 25 percent
|
||||
//Joshua Bloch "Effective Java, Second Edition", p. 283-284
|
||||
// local variable increases performance by 25 percent
|
||||
// Joshua Bloch "Effective Java, Second Edition", p. 283-284
|
||||
ThreadSafeDoubleCheckLocking result = INSTANCE;
|
||||
if (result == null) {
|
||||
synchronized (ThreadSafeDoubleCheckLocking.class) {
|
||||
|
@ -1,22 +1,20 @@
|
||||
package com.iluwatar.singleton;
|
||||
|
||||
/**
|
||||
* Thread-safe Singleton class.
|
||||
* The instance is lazily initialized and thus needs synchronization
|
||||
* Thread-safe Singleton class. The instance is lazily initialized and thus needs synchronization
|
||||
* mechanism.
|
||||
*
|
||||
* Note: if created by reflection then a singleton will not be created but multiple options in the same classloader
|
||||
* Note: if created by reflection then a singleton will not be created but multiple options in the
|
||||
* same classloader
|
||||
*/
|
||||
public class ThreadSafeLazyLoadedIvoryTower {
|
||||
|
||||
private static ThreadSafeLazyLoadedIvoryTower instance = null;
|
||||
|
||||
private ThreadSafeLazyLoadedIvoryTower() {
|
||||
}
|
||||
private ThreadSafeLazyLoadedIvoryTower() {}
|
||||
|
||||
/**
|
||||
* The instance gets created only when it is called for first time.
|
||||
* Lazy-loading
|
||||
* The instance gets created only when it is called for first time. Lazy-loading
|
||||
*/
|
||||
public synchronized static ThreadSafeLazyLoadedIvoryTower getInstance() {
|
||||
|
||||
|
@ -11,9 +11,9 @@ import com.iluwatar.singleton.App;
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
}
|
||||
@Test
|
||||
public void test() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
}
|
||||
}
|
||||
|
@ -12,68 +12,73 @@ import static org.junit.Assert.assertEquals;
|
||||
/**
|
||||
* This class provides several test case that test singleton construction.
|
||||
*
|
||||
* The first proves that multiple calls to the singleton getInstance object are the same when called in the SAME thread.
|
||||
* The second proves that multiple calls to the singleton getInstance object are the same when called in the DIFFERENT thread.
|
||||
* The first proves that multiple calls to the singleton getInstance object are the same when called
|
||||
* in the SAME thread. The second proves that multiple calls to the singleton getInstance object are
|
||||
* the same when called in the DIFFERENT thread.
|
||||
*
|
||||
*/
|
||||
public class LazyLoadedSingletonThreadSafetyTest {
|
||||
|
||||
private static final int NUM_THREADS = 5;
|
||||
private List<ThreadSafeLazyLoadedIvoryTower> threadObjects = Collections.synchronizedList(new ArrayList<>());
|
||||
private static final int NUM_THREADS = 5;
|
||||
private List<ThreadSafeLazyLoadedIvoryTower> threadObjects = Collections
|
||||
.synchronizedList(new ArrayList<>());
|
||||
|
||||
//NullObject class so Callable has to return something
|
||||
private class NullObject{private NullObject(){}}
|
||||
// NullObject class so Callable has to return something
|
||||
private class NullObject {
|
||||
private NullObject() {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_MultipleCallsReturnTheSameObjectInSameThread() {
|
||||
//Create several instances in the same calling thread
|
||||
ThreadSafeLazyLoadedIvoryTower instance1 = ThreadSafeLazyLoadedIvoryTower.getInstance();
|
||||
ThreadSafeLazyLoadedIvoryTower instance2 = ThreadSafeLazyLoadedIvoryTower.getInstance();
|
||||
ThreadSafeLazyLoadedIvoryTower instance3 = ThreadSafeLazyLoadedIvoryTower.getInstance();
|
||||
//now check they are equal
|
||||
assertEquals(instance1, instance1);
|
||||
assertEquals(instance1, instance2);
|
||||
assertEquals(instance2, instance3);
|
||||
assertEquals(instance1, instance3);
|
||||
@Test
|
||||
public void test_MultipleCallsReturnTheSameObjectInSameThread() {
|
||||
// Create several instances in the same calling thread
|
||||
ThreadSafeLazyLoadedIvoryTower instance1 = ThreadSafeLazyLoadedIvoryTower.getInstance();
|
||||
ThreadSafeLazyLoadedIvoryTower instance2 = ThreadSafeLazyLoadedIvoryTower.getInstance();
|
||||
ThreadSafeLazyLoadedIvoryTower instance3 = ThreadSafeLazyLoadedIvoryTower.getInstance();
|
||||
// now check they are equal
|
||||
assertEquals(instance1, instance1);
|
||||
assertEquals(instance1, instance2);
|
||||
assertEquals(instance2, instance3);
|
||||
assertEquals(instance1, instance3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_MultipleCallsReturnTheSameObjectInDifferentThreads()
|
||||
throws InterruptedException, ExecutionException {
|
||||
{// create several threads and inside each callable instantiate the singleton class
|
||||
ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||
|
||||
List<Callable<NullObject>> threadList = new ArrayList<>();
|
||||
for (int i = 0; i < NUM_THREADS; i++) {
|
||||
threadList.add(new SingletonCreatingThread());
|
||||
}
|
||||
|
||||
ExecutorService service = Executors.newCachedThreadPool();
|
||||
List<Future<NullObject>> results = service.invokeAll(threadList);
|
||||
|
||||
// wait for all of the threads to complete
|
||||
for (Future res : results) {
|
||||
res.get();
|
||||
}
|
||||
|
||||
// tidy up the executor
|
||||
executorService.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_MultipleCallsReturnTheSameObjectInDifferentThreads() throws InterruptedException, ExecutionException {
|
||||
{//create several threads and inside each callable instantiate the singleton class
|
||||
ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||
|
||||
List<Callable<NullObject>> threadList = new ArrayList<>();
|
||||
for (int i = 0; i < NUM_THREADS; i++) {
|
||||
threadList.add(new SingletonCreatingThread());
|
||||
}
|
||||
|
||||
ExecutorService service = Executors.newCachedThreadPool();
|
||||
List<Future<NullObject>> results = service.invokeAll(threadList);
|
||||
|
||||
//wait for all of the threads to complete
|
||||
for (Future res : results) {
|
||||
res.get();
|
||||
}
|
||||
|
||||
//tidy up the executor
|
||||
executorService.shutdown();
|
||||
}
|
||||
{//now check the contents that were added to threadObjects by each thread
|
||||
assertEquals(NUM_THREADS, threadObjects.size());
|
||||
assertEquals(threadObjects.get(0), threadObjects.get(1));
|
||||
assertEquals(threadObjects.get(1), threadObjects.get(2));
|
||||
assertEquals(threadObjects.get(2), threadObjects.get(3));
|
||||
assertEquals(threadObjects.get(3), threadObjects.get(4));
|
||||
}
|
||||
{// now check the contents that were added to threadObjects by each thread
|
||||
assertEquals(NUM_THREADS, threadObjects.size());
|
||||
assertEquals(threadObjects.get(0), threadObjects.get(1));
|
||||
assertEquals(threadObjects.get(1), threadObjects.get(2));
|
||||
assertEquals(threadObjects.get(2), threadObjects.get(3));
|
||||
assertEquals(threadObjects.get(3), threadObjects.get(4));
|
||||
}
|
||||
}
|
||||
|
||||
private class SingletonCreatingThread implements Callable<NullObject> {
|
||||
@Override
|
||||
public NullObject call() {
|
||||
//instantiate the thread safety class and add to list to test afterwards
|
||||
ThreadSafeLazyLoadedIvoryTower instance = ThreadSafeLazyLoadedIvoryTower.getInstance();
|
||||
threadObjects.add(instance);
|
||||
return new NullObject();//return null object (cannot return Void)
|
||||
}
|
||||
private class SingletonCreatingThread implements Callable<NullObject> {
|
||||
@Override
|
||||
public NullObject call() {
|
||||
// instantiate the thread safety class and add to list to test afterwards
|
||||
ThreadSafeLazyLoadedIvoryTower instance = ThreadSafeLazyLoadedIvoryTower.getInstance();
|
||||
threadObjects.add(instance);
|
||||
return new NullObject();// return null object (cannot return Void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user