单例模式中一个类只允许创建一个对象
一、应用场景
系统中只需要保持一份,例如配置信息。
二、加载方式
1.饿汉式
- 线程安全
 - 不支持延迟加载
 
private final static HungrySingleton hungrysingleton;
static {
        hungrysingleton=new HungrySingleton();
}
2.懒汉式
- 线程不安全,需要增加 synchronzed
 - 加锁后性能瓶颈
 
public synchronized static LazySingleton getInstance(){
        if(lazySingleton==null){
            lazySingleton=new LazySingleton();
        }
        return lazySingleton;
    }
3.双重检测
既支持延迟加载,又支持高并发
private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton=null;
public synchronized static LazyDoubleCheckSingleton getInstance(){
        if(lazyDoubleCheckSingleton==null){
            synchronized (LazyDoubleCheckSingleton.class){
                if(lazyDoubleCheckSingleton==null){
                    lazyDoubleCheckSingleton=new LazyDoubleCheckSingleton();
                    //1.分配内存给这个对象
                    //2.初始化对象
                    //3.设置lazyDoubleCheckSingleton指向刚才的地址
                }
            }
        }
        return lazyDoubleCheckSingleton;
    }
volatile 关键字用于禁止指令重排序,防止 layDoubleCheckSingleton 被其他线程使用
不过,只有很低版本的 JDK 才会有这个问题,高版本中将 new 操作设计为原子操作,不存在这个问题。
4.静态内部类
使用静态内部类,交给 JDK
//静态内部类
private static class InnerClass{
        private static StaticInnerClassSingleton staticInnerClassSingleton=new StaticInnerClassSingleton();
}
 //只有调用 getInstance 的时候,StaticInnerClassSingleton 才会被加载
public static final StaticInnerClassSingleton getInstance(){
        return InnerClass.staticInnerClassSingleton;
}
三、单例模式缺点
- 不支持面向对象特性,违背了基于接口而非实现的原则。
 - 隐藏类之间的依赖关系,可读性差。
 - 扩展性不友好。
 - 可测试性不友好,无法实现 mock 替换。
 - 单例不支持有参数的构造函数