[01][01][02] 单例模式详解

1. 定义

指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点

2. 适用场景

  • 确保任何情况下都绝对只有一个实例
  • ServletContext, ServletConfig, ApplicationContext, DBPool

3. 分类

  • 饿汉式单例
  • 懒汉式单例
  • 注册式单例
  • ThreadLocal单例

4. 饿汉式单例

在单例类首次加载时就创建实例

4.1 优/缺点

  • 优点: 不会存在线程不安全问题
  • 缺点: 浪费内存空间

4.2 饿汉式单例分类

  • 直接通过new创建实例
  • 通过static模块创建实例

4.2.1 直接通过new创建实例

public class HungrySingleton {

    private static final HungrySingleton hungrySingleton = new HungrySingleton();

    private HungrySingleton() {}

    public static HungrySingleton getInstance() {
        return hungrySingleton;
    }
}

4.2.2 通过static模块创建实例

public class HungryStaticSingleton {

    private static final HungryStaticSingleton hungrySingleton;

    private HungryStaticSingleton() {}

    static {
        hungrySingleton = new HungryStaticSingleton();
    }

    public static HungryStaticSingleton getInstance() {
        return hungrySingleton;
    }
}

5. 懒汉式单例

被外部调用时才创建实例

5.1 懒汉式单例分类

  • 简单懒汉式单例
  • 双重检查懒汉式单例
  • 静态内部类懒汉式单例

5.1.1 简单懒汉式单例

  • 在并发场景下存在线程安全问题
public class LazySimpleSingleton {

        private static LazySimpleSingleton lazySimpleSingleton = null;

        private LazySimpleSingleton(){}

        public static LazySimpleSingleton getInstance() {
            if (null == lazySimpleSingleton) {
                lazySimpleSingleton = new LazySimpleSingleton();
            }
            return lazySimpleSingleton;
        }
}

5.1.2 双重检查懒汉式单例

  • 通过synchronized和双重检查, 解决简单懒汉式单例存在的线程安全问题
public class LazyDoubleCheckSingleton {

        private static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;

        private LazyDoubleCheckSingleton(){}

        public static LazyDoubleCheckSingleton getInstance() {
            if (null == lazyDoubleCheckSingleton) {
                synchronized (LazyDoubleCheckSingleton.class) {
                    if (null == lazyDoubleCheckSingleton) {
                        lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
                    }
                }
            }
            return lazyDoubleCheckSingleton;
        }
}

5.1.3 静态内部类懒汉式单例

  • 全程没有用到synchronized
  • 巧妙利用了内部类的特性
  • JVM底层执行逻辑,完美的避免了线程安全问题
  • 存在被反射攻击的风险, 通过if (null != LazyHolder.LAZY) {解决反射问题
/**
 * 静态内部类懒汉式单例
 */
public class LazyInnerClassSingleton {

    private LazyInnerClassSingleton(){
        if (null != LazyHolder.LAZY) {
            throw new RuntimeException("禁止反射创建实例");
        }
    }

    // LazyHolder里面的逻辑需要等到外部方法调用时才执行
    // 全程没有用到synchronized
    // 巧妙利用了内部类的特性
    // JVM底层执行逻辑,完美的避免了线程安全问题
    public static LazyInnerClassSingleton getInstance() {
        return LazyHolder.LAZY;
    }

    private static class LazyHolder {
        private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
    }
}

5.1.3 注册式单例

将每一个实例都缓存到统一的容器中,使用唯一标识获取实例

发布了29 篇原创文章 · 获赞 10 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/csharpqiuqiu/article/details/100057156