【设计模式04】单例模式

前言

整个系统中只会出现要给实例,比如Spring中的Bean基本都是单例的

UML类图

代码示例

java 复制代码
package com.sw.learn.pattern.B_create.c_singleton;


public class Main {
    public static void main(String[] args) {
        // double check locking 线程安全+懒加载 ⭐️
//        SingletonDCL instance = SingletonDCL.getInstance();

        // 静态内部类 线程安全+懒加载 ⭐️⭐️
//        Singleton s1 = Singleton.getInstance();
//        Singleton s2 = Singleton.getInstance();
//        System.out.println(s1 == s2); // true

        // 枚举类  线程安全+饿汉式 ⭐️⭐️⭐️
//        SingletonEnum.INSTANCE.doSomething();

        // 基于枚举内部类的懒汉式单例模式 ⭐️⭐️⭐️⭐️
        BeanContainer instance2 = BeanContainer.getInstance();
        BeanContainer instance3 = BeanContainer.getInstance();
        System.out.println(instance2 == instance3); // true

    }
}

class Singleton {
    // 私有构造方法,防止外部实例化
    private Singleton() {
        System.out.println("Singleton constructor called.");
    }

    // 静态内部类,只有在第一次调用 getInstance() 时才会加载
    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }

    // 对外提供获取实例的方法
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

class SingletonDCL {

    // 使用 volatile 防止初始化时指令重排序,确保线程安全
    private static volatile SingletonDCL instance;

    private SingletonDCL() {
        System.out.println("SingletonDCL constructor called.");
    }

    public static SingletonDCL getInstance() {
        if (instance == null) { // 第一次检查(不加锁) 提高性能
            synchronized (SingletonDCL.class) {
                if (instance == null) { // 第二次检查(加锁后再检查) 防止多个线程同时通过第一层检查后并发创建;
                    instance = new SingletonDCL();
                }
            }
        }
        return instance;
    }
}

enum SingletonEnum {
    INSTANCE;

    public void doSomething() {
        System.out.println("Doing something with enum singleton.");
    }
}

// 枚举编译后效果
//final class SingletonEnum2 extends Enum<SingletonEnum2> {
//    public static final SingletonEnum2 INSTANCE = new SingletonEnum2("INSTANCE", 0);
//
//    private SingletonEnum2(String name, int ordinal) {
//        super(name, ordinal);
//    }
//}

class BeanContainer {
    // 调用getInstance方法时,第一次初始化ContainerHolder枚举类,初始的时候执行构造方法,实例化BeanContainer对象

    /**
     * 第一步:调用 ContainerHolder.HOLDER
     * JVM 首次访问 ContainerHolder 时会触发类加载。
     * <p>
     * 内部类不会在外部类加载时加载,只有在首次访问时才加载(这就是懒加载)。
     * <p>
     * 枚举类加载也是线程安全的,JVM 会保证枚举类只加载一次,不会有并发初始化问题。
     *
     * @return
     */
    public static BeanContainer getInstance() {
        return ContainerHolder.HOLDER.instance;
    }

    private enum ContainerHolder {
        HOLDER; // 容器,装载了BeanContainer对象
        /**
         * 第二步:加载 enum ContainerHolder
         * 枚举类 ContainerHolder 加载时,会创建一个 enum 常量 HOLDER。
         */
        private BeanContainer instance;

        ContainerHolder() {
            instance = new BeanContainer(); // 会被执行一次,初始化 instance, 即 ContainerHolder.HOLDER 被加载时。
        }
    }
}
相关推荐
杨充2 小时前
10.可测试性实战设计
设计模式·开源·代码规范
杨充2 小时前
9.重构十二式的实战
设计模式·开源·代码规范
杨充2 小时前
6.设计原则的全景图
设计模式·开源·全栈
杨充2 小时前
2.面向对象的特性
设计模式
杨充2 小时前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充2 小时前
8.反模式与坏味道
设计模式·开源·代码规范
杨充2 小时前
3.接口vs抽象类比较
设计模式
咖啡八杯5 小时前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法
zjun10016 小时前
C++:单例模式
c++·单例模式