设计模式-创建型模式-单例模式

0 引言

创建型模式(Creational Pattern)关注对象的创建过程,是一类最常用的设计模式,每个创建型模式都通过采用不同的解决方案来回答3个问题:创建什么(What),由谁创建(Who)和何时创建(When)。

1 单例模式

单例模式有3个要点:①某个类只能有一个实例;②它必须自行创建这个实例;③它必须自行向整个系统提供这个实例。

单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。DP

1.1 饿汉单例模式

在类加载的时候就已经实例化,并且创建单例对象,以后直接使用即可。这种模式下,类加载较慢,但获取对象的速度快,且线程安全。

复制代码
public class HungrySingleton {
    // 在类加载时就已经完成了实例的初始化
    private static final HungrySingleton instance = new HungrySingleton();

    // 构造器私有,防止外部通过new关键字创建对象
    private HungrySingleton() {}

    // 提供全局访问点
    public static HungrySingleton getInstance() {
        return instance;
    }

    // 如果需要,可以添加其他方法或属性
    public void showMessage() {
        System.out.println("This is an instance of HungrySingleton.");
    }

    public static void main(String[] args) {
        // 获取单例对象
        HungrySingleton instance1 = HungrySingleton.getInstance();
        HungrySingleton instance2 = HungrySingleton.getInstance();

        // 输出实例,验证是否为同一个对象
        System.out.println(instance1);
        System.out.println(instance2);

        // 验证是否为同一个对象的引用
        System.out.println(instance1 == instance2);

        // 调用实例方法
        instance1.showMessage();
    }
}

1.2 懒汉单例模式

一开始不会实例化,什么时候用就什么时候进行实例化。这种模式下,类加载较快,但获取对象的速度稍慢,且可能在多线程情况下出现线程安全问题。

存在线程安全问题,

复制代码
public class LazySingleton {
    // 私有静态实例,初始化为null
    private static LazySingleton instance = null;

    // 私有构造方法,防止外部通过new关键字创建对象
    private LazySingleton() {}

    // 提供全局访问点
    public static  LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }

    // 如果需要,可以添加其他方法或属性
    public void showMessage() {
        System.out.println("This is an instance of LazySingleton.");
    }

    public static void main(String[] args) {
        // 获取单例对象
        LazySingleton instance1 = LazySingleton.getInstance();

        // 调用实例方法
        instance1.showMessage();
    }
}

加锁,

复制代码
public class LazySingleton {
    // 私有静态实例,初始化为null
    private static LazySingleton instance = null;

    // 私有构造方法,防止外部通过new关键字创建对象
    private LazySingleton() {}

    // 同步方法,提供全局访问点
    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }

    // 如果需要,可以添加其他方法或属性
    public void showMessage() {
        System.out.println("This is an instance of LazySingleton.");
    }

    public static void main(String[] args) {
        // 获取单例对象
        LazySingleton instance1 = LazySingleton.getInstance();
        LazySingleton instance2 = LazySingleton.getInstance();

        // 输出实例,验证是否为同一个对象
        System.out.println(instance1);
        System.out.println(instance2);

        // 验证是否为同一个对象的引用
        System.out.println(instance1 == instance2);

        // 调用实例方法
        instance1.showMessage();
    }
}

然而,同步方法会导致性能下降,因为每次调用getInstance()方法时都需要进行同步。为了解决这个问题,可以使用**双重校验锁(Double-Checked Locking,DCL)**来实现更高效的懒汉单例模式:现在这样,我们不用让线程每次都加锁,而只是在实例未被创建的时候再加锁处理。同时也能保证多线程的安全。这种做法被称为Double-Check Locking(双重锁定)。

复制代码
public class LazySingletonWithDCL {
    // volatile关键字确保instance在多线程环境下被正确初始化
    private static volatile LazySingletonWithDCL instance = null;

    // 私有构造方法,防止外部通过new关键字创建对象
    private LazySingletonWithDCL() {}

    // 提供全局访问点
    public static LazySingletonWithDCL getInstance() {
        if (instance == null) {
            // 第一次检查
            synchronized (LazySingletonWithDCL.class) {
                if (instance == null) {
                    // 第二次检查
                    instance = new LazySingletonWithDCL();
                }
            }
        }
        return instance;
    }

    // 如果需要,可以添加其他方法或属性
    public void showMessage() {
        System.out.println("This is an instance of LazySingletonWithDCL.");
    }

    public static void main(String[] args) {
        // 获取单例对象
        LazySingletonWithDCL instance1 = LazySingletonWithDCL.getInstance();
        LazySingletonWithDCL instance2 = LazySingletonWithDCL.getInstance();

        // 输出实例,验证是否为同一个对象
        System.out.println(instance1);
        System.out.println(instance2);

        // 验证是否为同一个对象的引用
        System.out.println(instance1 == instance2);

        // 调用实例方法
        instance1.showMessage();
    }
}

使用内部静态类来实现单例模式,这种方式的特点是利用了类加载机制来保证初始化实例时只有一个实例被创建,并且由于JVM的类加载机制,这种方式是线程安全的。只适合java。

复制代码
public class Singleton {
    // 私有构造方法,防止外部通过new关键字创建对象
    private Singleton() {}

    // 静态内部类,持有单例对象
    private static class SingletonHolder {
        // 静态初始化器,由JVM保证线程安全
        private static final Singleton INSTANCE = new Singleton();
    }

    // 提供全局访问点
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }

    // 如果需要,可以添加其他方法或属性
    public void showMessage() {
        System.out.println("This is an instance of Singleton.");
    }

    public static void main(String[] args) {
        // 获取单例对象
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();

        // 输出实例,验证是否为同一个对象
        System.out.println(instance1);
        System.out.println(instance2);

        // 验证是否为同一个对象的引用
        System.out.println(instance1 == instance2);

        // 调用实例方法
        instance1.showMessage();
    }
}
相关推荐
咖啡八杯15 小时前
GoF设计模式——备忘录模式
java·后端·spring·设计模式
槑有老呆19 小时前
从 Prompt Engineering 到 Harness Engineering:AI 编程的下一次跃迁
设计模式
HjhIron1 天前
从Prompt到Context:大模型应用开发的范式转移
设计模式·aigc·ai编程
咖啡八杯3 天前
GoF设计模式——中介者模式
java·后端·spring·设计模式
胡萝卜术3 天前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
亦暖筑序4 天前
Java 8老系统Browser Agent实战:三层拦截把AI操作后台变成可审计流程
java·后端·设计模式
青禾网络6 天前
Web 前端如何接入 AI 音效生成:从零到可用的完整方案
人工智能·设计模式
ZJPRENO7 天前
吃透软件开发六大设计原则,告别烂代码
设计模式
咖啡八杯7 天前
GoF设计模式——命令模式
java·设计模式·架构
花椒技术8 天前
HJPusher / HJPlayer SDK 实践:我们为什么把直播推播链路拆成一套可复用能力
设计模式·harmonyos·直播