BAEL 1639: added singleton examples and test. (#3977)

This commit is contained in:
Donato Rimenti 2018-04-21 18:51:14 +02:00 committed by Grzegorz Piwowarek
parent 5b5386636b
commit 5f83980363
6 changed files with 279 additions and 0 deletions

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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());
}
}