根据**Design Patterns - Elements of Reusable Object-Oriented Software(即:设计模式 可复用面向对象软件基础)**中所写
单例模式(Singleton Pattern)为一个创建型模式【这些设计模式提供了一种在创建对象的 同时隐藏创建逻辑的方式,而不是使用new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。】
**单例模式:**其意图是,保证一个类仅有一个实例,并提供一个提供一个访问它的全局访问点, 当一个全局使用的类频繁的创建与销毁时使用单例能很好的解决该问题。
单例模式的关键:构造函数私有化 private
懒汉模式
public class LazySingleton {
//类调用时才生成对象 延迟加载
private static LazySingleton instance;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
由于不支持多线程 所以严格意义上来说不算单例模式这种方式 lazy loading(延迟初始化) 很明显,不要求线程安全,在多线程不能正常工作
public class LazySingletonSafe {
private static LazySingletonSafe instance;
private LazySingletonSafe() {
}
public static synchronized LazySingletonSafe getInstance() {
if (instance == null) {
instance = new LazySingletonSafe();
}
return instance;
}
}
线程安全效率低
public class LazySingletonNoSafe {
private static LazySingletonNoSafe instance;
private LazySingletonNoSafe(){}
public static LazySingletonNoSafe getInstance() {
if (instance == null) {
synchronized (LazySingletonNoSafe.class) {
instance = getInstance();
}
}
return instance;
}
线程安全 但会产生多个实例
饿汉模式
public class CrazySingleton {
/**即时加载 类加载时就生成对象*/
private static CrazySingleton instance = new CrazySingleton();
private CrazySingleton() {
}
public static CrazySingleton getInstance() {
return instance;
}
线程安全 实例在类初始化的时候就创建了,如果在整个项目中都没有使用到该类,就会创建内存空间的浪费。
```javascript
public class CrazyStaticCodeSingleton {
private static CrazyStaticCodeSingleton instance = null;
//静态代码块进行初始化
static {
instance = new CrazyStaticCodeSingleton();
}
private CrazyStaticCodeSingleton(){}
public static CrazyStaticCodeSingleton getInstance() {
return instance;
}
}
双重检查锁
public class DCLSingleton {
private volatile static DCLSingleton instance;
private DCLSingleton() {
}
public static DCLSingleton getInstance() {
if (instance == null) {
synchronized (DCLSingleton.class) {
if (instance == null) {
instance = new DCLSingleton();
}
}
}
return instance;
}
}
线程安全 volatile关键字能够禁止指令重排,保证在写操作没有完成之前不能调用读操作。
静态内部类
public class StaticSingleton {
private static class SingletonHolder{
private static final StaticSingleton INSTANCE = new StaticSingleton();
}
private StaticSingleton(){}
public static final StaticSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
线程安全 利用静态内部类的初始化与外部类初始化时分开的,在没有调用getInstance()方法之前,静态内部类不会初始化,在第一次调用该方法后就会产生位唯一一个实例
枚举
public enum EnumSingleton {
INSTANCE;
public void testMethod() {
}
}
考虑多线程问题 单例类构造方法要设置为private类型禁止外界new创建 如果类可序列化,考虑反序列化生成多个实例问题,解决方案如下
考虑多线程问题
2、单例类构造方法要设置为private类型禁止外界new创建
private Singleton() {}
3、如果类可序列化,考虑反序列化生成多个实例问题,解决方案如下
private Object readResolve() throws ObjectStreamException {
// instead of the object we're on, return the class variable INSTANCE
return INSTANCE;
}
枚举类型,无线程安全问题,避免反序列华创建新的实例,很少使用。