操作系统-懒汉式单例模式

懒汉式单例模式的主要好处有以下几点:

  1. 1.资源利用效率高:

    只有在第一次调用 getInstance() 方法时才创建实例对象,而不是在类加载时就创建。这可以节省系统资源。

  2. 2.延迟加载:

    实例对象的创建被延迟到第一次使用时,可以减少系统启动时的资源消耗。

  3. 3.线程安全:

    这种实现方式在多线程环境下是线程安全的。通过对 getInstance() 方法的同步控制,可以确保在多个线程同时访问时,只有一个线程能够创建实例对象。

第一版懒汉模式的代码:

好处:只有instance为空的时候才new一个对象。

缺点:这是线程不安全的。

原因:如果两个线程同时执行 if (instance == null) 检查,并且 instance 恰好是 null,那么两个线程都会创建新的 Singleton 实例,违背了单例模式的设计目的。

java 复制代码
public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

第二版懒汉模式的代码:

加synchronized关键字进行加锁操作。

好处:这样可以确保在同一时刻只有一个线程能够创建实例对象,从而保证线程安全。

缺点:

1.在高并发的场景下,对 getInstance() 方法加synchronized关键字会带来性能问题。

2.因为每次调用 getInstance() 方法都需要获取锁,这会导致不必要的性能开销。

java 复制代码
public static synchronized Singleton getInstance() {
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
}

最终版懒汉模式的代码:

为了解决性能问题,可以采用双重检查锁定(Double-Checked Locking, DCL)的方式

在这种实现中,我们先进行一次 instance == null 的检查,如果为 null,才进入同步代码块。在同步代码块内部,再次检查 instance 是否为 null,如果是则创建实例。这样可以大大减少对 synchronized 的使用,提高性能。

java 复制代码
public static Singleton getInstance() {
    if (instance == null) {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton();
            }
        }
    }
    return instance;
}

完整代码:

java 复制代码
class SingletonLazy{
     private static volatile SingletonLazy instance = null;
     private static Object locker = new Object();
     public static SingletonLazy getInstance(){
        if(instance==null){
            synchronized(locker){
                if(instance==null){
                    instance = new SingletonLazy();
                }
            }

        }
         return instance;
     }
     private SingletonLazy(){}
}
public class test1 {
    public static void main(String[] args) {
        SingletonLazy s1 = SingletonLazy.getInstance();
        SingletonLazy s2 = SingletonLazy.getInstance();
        System.out.println(s1 == s2);
    }
}

返回的结果是true为什么呢:

在单例模式中,SingletonLazy 类有一个私有的构造方法,以防止外部直接创建实例。取而代之的是,我们需要通过 getInstance() 方法来获取该类的单例实例。

当我们第一次调用 SingletonLazy.getInstance() 时,方法内部会检查 instance 变量是否为 null。如果是 null,则会创建一个新的 SingletonLazy 实例,并将其赋值给 instance 变量。

在第二次调用 SingletonLazy.getInstance() 时,由于 instance 变量已经不为 null了,所以方法会直接返回之前创建的那个实例。

因此,s1s2 变量都引用了同一个 SingletonLazy 实例,这是单例模式的设计目标。

所以,这段代码只会创建一个 SingletonLazy 实例,而不是两个。s1s2 变量最终都指向同一个实例。

作者最开始理解,两个对象指向的引用不同为啥会返回true呢,问了AI就知道为啥了。上面就是原因。

总结:

在线程不安全的单例模式实现中,确实可能会创建两个以上的对象实例。这是因为在并发环境下,多个线程可能同时检查 instance 变量是否为 null,并且同时创建新的实例。

让我们来看一下不同情况下会发生什么:

  1. 线程安全的单例模式:

    • 第一次调用 getInstance() 时,会创建一个新的实例并赋值给 instance 变量。
    • 后续调用 getInstance() 时,由于 instance 变量已经不为 null,直接返回之前创建的实例。
    • 因此,只会创建一个实例。
  2. 线程不安全的单例模式:

    • 多个线程同时进入 getInstance() 方法,并且都检查到 instance 变量为 null
    • 这些线程会同时创建新的实例,导致最终存在多个实例。
    • 这违背了单例模式的设计目标。

所以,在线程不安全的情况下,可能会创建两个或更多的对象实例,这就破坏了单例模式的特性。

这就是为什么在实现单例模式时,我们需要特别注意线程安全的问题。通过同步、双重检查锁等技术,我们可以确保只有一个实例被创建,从而保证单例模式的正确性。

相关推荐
阿让啊几秒前
bootloader+APP中,有些APP引脚无法正常使用?
c语言·开发语言·stm32·单片机·嵌入式硬件
卡戎-caryon3 分钟前
【Linux网络与网络编程】03.UDP Socket编程
linux·服务器·网络·笔记·单例模式·udp·网络通信
努力的搬砖人.4 分钟前
maven如何使用
java·后端·面试·maven
饕餮ing4 分钟前
C++的UDP连接解析域名地址错误
开发语言·c++·udp
莲动渔舟5 分钟前
Nyquist插件基础:打印格式化字符串(LISP语言)
开发语言·lisp·音频处理·audacity
风象南7 分钟前
SpringBoot中6种跨域请求解决方案
java·spring boot·后端
vivo互联网技术9 分钟前
活动中台系统慢 SQL 治理实践
java·数据库·后端
满怀101517 分钟前
Python入门(5):异常处理
开发语言·python
是小李呀~20 分钟前
【工作梳理】怎么把f12里面的东西导入到postman
java
攀小黑20 分钟前
Java 多线程加锁 synchronized 关键字 字符串当做key
java·开发语言