单例模式

单例模式UML类图

单例模式UML类图

单例模式java实现

/**
* Singleton class. Eagerly initialized static instance guarantees thread safety.
*/
public final class IvoryTower {

/**
* Private constructor so nobody can instantiate the class.
*/
private IvoryTower() {
}

/**
* Static to class instance of the class.
*/
private static final IvoryTower INSTANCE = new IvoryTower();

/**
* To be called by user to obtain instance of the class.
*
* @return instance of the singleton.
*/
public static IvoryTower getInstance() {
return INSTANCE;
}
}

/**
* <p>Double check locking.</p>
*
* <p>http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html</p>
*
* <p>Broken under Java 1.4.</p>
*
* @author mortezaadi@gmail.com
*/
public final class ThreadSafeDoubleCheckLocking {

private static volatile ThreadSafeDoubleCheckLocking instance;

private static boolean flag = true;

/**
* private constructor to prevent client from instantiating.
*/
private ThreadSafeDoubleCheckLocking() {
// to prevent instantiating by Reflection call
if (flag) {
flag = false;
} else {
throw new IllegalStateException("Already initialized.");
}
}

/**
* Public accessor.
*
* @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

var result = instance;
// Check if singleton instance is initialized.
// If it is initialized then we can return the instance.
if (result == null) {
// It is not initialized but we cannot be sure because some other thread might have
// initialized it in the meanwhile.
// So to make sure we need to lock on an object to get mutual exclusion.
synchronized (ThreadSafeDoubleCheckLocking.class) {
// Again assign the instance to local variable to check if it was initialized by some
// other thread while current thread was blocked to enter the locked zone.
// If it was initialized then we can return the previously created instance
// just like the previous null check.
result = instance;
if (result == null) {
// The instance is still not initialized so we can safely
// (no other thread can enter this zone)
// create an instance and make it our singleton instance.
instance = result = new ThreadSafeDoubleCheckLocking();
}
}
}
return result;
}
}

/**
* <p>Thread-safe Singleton class. The instance is lazily initialized and thus needs synchronization
* mechanism.</p>
*
* <p>Note: if created by reflection then a singleton will not be created but multiple options
* in the same classloader</p>
*/
public final class ThreadSafeLazyLoadedIvoryTower {

private static ThreadSafeLazyLoadedIvoryTower instance;

private ThreadSafeLazyLoadedIvoryTower() {
// protect against instantiation via reflection
if (instance == null) {
instance = this;
} else {
throw new IllegalStateException("Already initialized.");
}
}

/**
* The instance gets created only when it is called for first time. Lazy-loading
*/
public static synchronized ThreadSafeLazyLoadedIvoryTower getInstance() {
if (instance == null) {
instance = new ThreadSafeLazyLoadedIvoryTower();
}

return instance;
}
}

/**
* <p>Enum based singleton implementation. Effective Java 2nd Edition (Joshua Bloch) p. 18</p>
*
* <p>This implementation is thread safe, however adding any other method and its thread safety
* is developers responsibility.</p>
*/
public enum EnumIvoryTower {

INSTANCE;

@Override
public String toString() {
return getDeclaringClass().getCanonicalName() + "@" + hashCode();
}
}

/**
* <p>The Initialize-on-demand-holder idiom is a secure way of creating a lazy initialized singleton
* object in Java.</p>
*
* <p>The technique is as lazy as possible and works in all known versions of Java. It takes
* advantage of language guarantees about class initialization, and will therefore work correctly
* in all Java-compliant compilers and virtual machines.</p>
*
* <p>The inner class is referenced no earlier (and therefore loaded no earlier by the class loader)
* than the moment that getInstance() is called. Thus, this solution is thread-safe without
* requiring special language constructs (i.e. volatile or synchronized).</p>
*
*/
public final class InitializingOnDemandHolderIdiom {

/**
* Private constructor.
*/
private InitializingOnDemandHolderIdiom() {
}

/**
* Sigleton instance.
*
* @return Singleton instance
*/
public static InitializingOnDemandHolderIdiom getInstance() {
return HelperHolder.INSTANCE;
}

/**
* Provides the lazy-loaded Singleton instance.
*/
private static class HelperHolder {
private static final InitializingOnDemandHolderIdiom INSTANCE =
new InitializingOnDemandHolderIdiom();
}
}

/**
* <p>Singleton pattern ensures that the class can have only one existing instance per Java
* classloader instance and provides global access to it.</p>
*
* <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.</p>
*
* <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.</p>
*
* <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</p>
*
* <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.</p>
*
* <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.</p>
*
* <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.</p>
*/
public class App {

private static final Logger LOGGER = LoggerFactory.getLogger(App.class);

/**
* Program entry point.
*
* @param args command line args
*/
public static void main(String[] args) {

// eagerly initialized singleton
var ivoryTower1 = IvoryTower.getInstance();
var ivoryTower2 = IvoryTower.getInstance();
LOGGER.info("ivoryTower1={}", ivoryTower1);
LOGGER.info("ivoryTower2={}", ivoryTower2);

// lazily initialized singleton
var threadSafeIvoryTower1 = ThreadSafeLazyLoadedIvoryTower.getInstance();
var threadSafeIvoryTower2 = ThreadSafeLazyLoadedIvoryTower.getInstance();
LOGGER.info("threadSafeIvoryTower1={}", threadSafeIvoryTower1);
LOGGER.info("threadSafeIvoryTower2={}", threadSafeIvoryTower2);

// enum singleton
var enumIvoryTower1 = EnumIvoryTower.INSTANCE;
var enumIvoryTower2 = EnumIvoryTower.INSTANCE;
LOGGER.info("enumIvoryTower1={}", enumIvoryTower1);
LOGGER.info("enumIvoryTower2={}", enumIvoryTower2);

// double checked locking
var dcl1 = ThreadSafeDoubleCheckLocking.getInstance();
LOGGER.info(dcl1.toString());
var dcl2 = ThreadSafeDoubleCheckLocking.getInstance();
LOGGER.info(dcl2.toString());

// initialize on demand holder idiom
var demandHolderIdiom = InitializingOnDemandHolderIdiom.getInstance();
LOGGER.info(demandHolderIdiom.toString());
var demandHolderIdiom2 = InitializingOnDemandHolderIdiom.getInstance();
LOGGER.info(demandHolderIdiom2.toString());
}
}