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

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

  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
    • 这些线程会同时创建新的实例,导致最终存在多个实例。
    • 这违背了单例模式的设计目标。

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

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

相关推荐
向宇it12 分钟前
【unity小技巧】Unity 四叉树算法实现空间分割、物体存储并进行查询和碰撞检测
开发语言·算法·游戏·unity·游戏引擎
我真的太难了啊16 分钟前
学习QT第二天
开发语言·qt·学习
伏虎山真人19 分钟前
QT程序开机自启方案
开发语言·qt
2401_8576009519 分钟前
企业OA管理系统:Spring Boot技术实践与案例分析
java·spring boot·后端
running up that hill24 分钟前
数据库中的增删改查操作、聚合函数、内置函数、分组查询
java·数据库·sql·mysql
潜洋27 分钟前
Spring Boot 教程之六:Spring Boot - 架构
java·spring boot·后端·架构
lsx20240629 分钟前
Ruby 模块(Module)
开发语言
希忘auto31 分钟前
详解RabbitMQ在Ubuntu上的安装
java·rabbitmq
豆包MarsCode38 分钟前
我用豆包MarsCode IDE 做了一个 CSS 权重小组件
开发语言·前端·javascript·css·ide·html
铅华尽39 分钟前
Java---JDBC案例--手机信息管理系统
java·开发语言·智能手机