BAEL 1639: added singleton examples and test. (#3977)
This commit is contained in:
parent
5b5386636b
commit
5f83980363
|
@ -0,0 +1,38 @@
|
||||||
|
package com.baeldung.designpatterns.singleton.synchronization;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Double-checked locking design pattern applied to a singleton.
|
||||||
|
*
|
||||||
|
* @author Donato Rimenti
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DclSingleton {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current instance of the singleton.
|
||||||
|
*/
|
||||||
|
private static volatile DclSingleton instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to avoid instantiation.
|
||||||
|
*/
|
||||||
|
private DclSingleton() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current instance of the singleton.
|
||||||
|
*
|
||||||
|
* @return the current instance of the singleton
|
||||||
|
*/
|
||||||
|
public static DclSingleton getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
synchronized (DclSingleton.class) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new DclSingleton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.baeldung.designpatterns.singleton.synchronization;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draconian singleton. The method to get the instance is synchronized.
|
||||||
|
*
|
||||||
|
* @author Donato Rimenti
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DraconianSingleton {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current instance of the singleton.
|
||||||
|
*/
|
||||||
|
private static DraconianSingleton instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to avoid instantiation.
|
||||||
|
*/
|
||||||
|
private DraconianSingleton() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current instance of the singleton.
|
||||||
|
*
|
||||||
|
* @return the current instance of the singleton
|
||||||
|
*/
|
||||||
|
public static synchronized DraconianSingleton getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new DraconianSingleton();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.baeldung.designpatterns.singleton.synchronization;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Singleton with early initialization. Inlines the singleton instance
|
||||||
|
* initialization.
|
||||||
|
*
|
||||||
|
* @author Donato Rimenti
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class EarlyInitSingleton {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current instance of the singleton.
|
||||||
|
*/
|
||||||
|
private static final EarlyInitSingleton INSTANCE = new EarlyInitSingleton();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to avoid instantiation.
|
||||||
|
*/
|
||||||
|
private EarlyInitSingleton() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current instance of the singleton.
|
||||||
|
*
|
||||||
|
* @return the current instance of the singleton
|
||||||
|
*/
|
||||||
|
public static EarlyInitSingleton getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.baeldung.designpatterns.singleton.synchronization;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum singleton pattern. Uses an enum to hold a reference to the singleton
|
||||||
|
* instance.
|
||||||
|
*
|
||||||
|
* @author Donato Rimenti
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum EnumSingleton {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current instance of the singleton.
|
||||||
|
*/
|
||||||
|
INSTANCE;
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.baeldung.designpatterns.singleton.synchronization;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization on demand singleton pattern. Uses a nested static class to
|
||||||
|
* hold a reference to the singleton instance.
|
||||||
|
*
|
||||||
|
* @author Donato Rimenti
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class InitOnDemandSingleton {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holder for a singleton instance.
|
||||||
|
*
|
||||||
|
* @author Donato Rimenti
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static class InstanceHolder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current instance of the singleton.
|
||||||
|
*/
|
||||||
|
private static final InitOnDemandSingleton INSTANCE = new InitOnDemandSingleton();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to avoid instantiation.
|
||||||
|
*/
|
||||||
|
private InitOnDemandSingleton() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current instance of the singleton.
|
||||||
|
*
|
||||||
|
* @return the current instance of the singleton
|
||||||
|
*/
|
||||||
|
public static InitOnDemandSingleton getInstance() {
|
||||||
|
return InstanceHolder.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
package com.baeldung.designpatterns.singleton.synchronization;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the singleton synchronization package with the same name.
|
||||||
|
*
|
||||||
|
* @author Donato Rimenti
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SingletonSynchronizationUnitTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of the thread pools used.
|
||||||
|
*/
|
||||||
|
private static final int POOL_SIZE = 1_000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of tasks to submit.
|
||||||
|
*/
|
||||||
|
private static final int TASKS_TO_SUBMIT = 1_000_000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the thread-safety of {@link DraconianSingleton}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void givenDraconianSingleton_whenMultithreadInstancesEquals_thenTrue() {
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(POOL_SIZE);
|
||||||
|
Set<DraconianSingleton> resultSet = Collections.synchronizedSet(new HashSet<DraconianSingleton>());
|
||||||
|
|
||||||
|
// Submits the instantiation tasks.
|
||||||
|
for (int i = 0; i < TASKS_TO_SUBMIT; i++) {
|
||||||
|
executor.submit(() -> resultSet.add(DraconianSingleton.getInstance()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since the instance of the object we inserted into the set is always
|
||||||
|
// the same, the size should be one.
|
||||||
|
Assert.assertEquals(1, resultSet.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the thread-safety of {@link DclSingleton}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void givenDclSingleton_whenMultithreadInstancesEquals_thenTrue() {
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(POOL_SIZE);
|
||||||
|
Set<DclSingleton> resultSet = Collections.synchronizedSet(new HashSet<DclSingleton>());
|
||||||
|
|
||||||
|
// Submits the instantiation tasks.
|
||||||
|
for (int i = 0; i < TASKS_TO_SUBMIT; i++) {
|
||||||
|
executor.submit(() -> resultSet.add(DclSingleton.getInstance()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since the instance of the object we inserted into the set is always
|
||||||
|
// the same, the size should be one.
|
||||||
|
Assert.assertEquals(1, resultSet.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the thread-safety of {@link EarlyInitSingleton}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void givenEarlyInitSingleton_whenMultithreadInstancesEquals_thenTrue() {
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(POOL_SIZE);
|
||||||
|
Set<EarlyInitSingleton> resultSet = Collections.synchronizedSet(new HashSet<EarlyInitSingleton>());
|
||||||
|
|
||||||
|
// Submits the instantiation tasks.
|
||||||
|
for (int i = 0; i < TASKS_TO_SUBMIT; i++) {
|
||||||
|
executor.submit(() -> resultSet.add(EarlyInitSingleton.getInstance()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since the instance of the object we inserted into the set is always
|
||||||
|
// the same, the size should be one.
|
||||||
|
Assert.assertEquals(1, resultSet.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the thread-safety of {@link InitOnDemandSingleton}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void givenInitOnDemandSingleton_whenMultithreadInstancesEquals_thenTrue() {
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(POOL_SIZE);
|
||||||
|
Set<InitOnDemandSingleton> resultSet = Collections.synchronizedSet(new HashSet<InitOnDemandSingleton>());
|
||||||
|
|
||||||
|
// Submits the instantiation tasks.
|
||||||
|
for (int i = 0; i < TASKS_TO_SUBMIT; i++) {
|
||||||
|
executor.submit(() -> resultSet.add(InitOnDemandSingleton.getInstance()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since the instance of the object we inserted into the set is always
|
||||||
|
// the same, the size should be one.
|
||||||
|
Assert.assertEquals(1, resultSet.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the thread-safety of {@link EnumSingleton}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void givenEnumSingleton_whenMultithreadInstancesEquals_thenTrue() {
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(POOL_SIZE);
|
||||||
|
Set<EnumSingleton> resultSet = Collections.synchronizedSet(new HashSet<EnumSingleton>());
|
||||||
|
|
||||||
|
// Submits the instantiation tasks.
|
||||||
|
for (int i = 0; i < TASKS_TO_SUBMIT; i++) {
|
||||||
|
executor.submit(() -> resultSet.add(EnumSingleton.INSTANCE));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since the instance of the object we inserted into the set is always
|
||||||
|
// the same, the size should be one.
|
||||||
|
Assert.assertEquals(1, resultSet.size());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue