欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > 单例模式-3-双检锁/双重校验锁(DCL,即 double-checked locking)

单例模式-3-双检锁/双重校验锁(DCL,即 double-checked locking)

2025/4/16 13:29:45 来源:https://blog.csdn.net/sunyaox/article/details/147243850  浏览:    关键词:单例模式-3-双检锁/双重校验锁(DCL,即 double-checked locking)

以下是对这段代码的详细解释,这是一种实现 双重检查锁定(Double-Checked Locking) 的单例模式:


1. 类的定义

public class Singleton {private volatile static Singleton singleton;private Singleton() {}public static Singleton getSingleton() {if (singleton == null) {synchronized (Singleton.class) {if (singleton == null) {singleton = new Singleton();}}}return singleton;}
}

2. 代码逐步解析

2.1. private volatile static Singleton singleton;
  • private:确保 singleton 变量只能在 Singleton 类内部访问,防止外部直接修改。
  • static:确保 singleton 是类级别的变量,所有实例共享同一个变量。
  • volatile:保证多线程环境下的可见性和有序性。
    • 可见性:当一个线程修改了 singleton 的值,其他线程能够立即看到修改后的值。
    • 有序性:防止指令重排序问题(即对象未完全初始化时,其他线程可能访问到未初始化的对象)。

2.2. private Singleton() {}
  • 将构造方法声明为 private,防止外部通过 new 关键字创建实例。
  • 这是单例模式的核心,确保只能通过类的静态方法获取实例。

2.3. public static Singleton getSingleton()

这是获取单例实例的公共方法,包含了双重检查锁定的逻辑。


2.4. if (singleton == null)
  • 第一次检查:在进入同步块之前,检查 singleton 是否为 null
    • 如果 singleton 已经被初始化,则直接返回实例,避免不必要的同步开销。
    • 如果 singletonnull,说明实例尚未创建,进入同步块。

2.5. synchronized (Singleton.class)
  • 同步块:对 Singleton.class 加锁,确保只有一个线程能够进入同步块,避免多个线程同时创建实例。
  • 这是双重检查锁定的关键,确保线程安全。

2.6. if (singleton == null)
  • 第二次检查:进入同步块后,再次检查 singleton 是否为 null
    • 这是因为可能有多个线程在第一次检查时通过了 if (singleton == null),但只有一个线程能够进入同步块。
    • 如果没有第二次检查,可能会导致多个线程创建多个实例。

2.7. singleton = new Singleton();
  • 创建单例实例。
  • 由于 volatile 的作用,确保对象初始化完成后,其他线程能够正确看到 singleton 的值。

2.8. return singleton;
  • 返回单例实例。

3. 为什么需要双重检查锁定?

双重检查锁定的目的是在保证线程安全的同时,尽量减少同步的开销:

  1. 第一次检查:避免每次调用 getSingleton() 都进入同步块,提高性能。
  2. 第二次检查:确保在多线程环境下,只有一个线程能够创建实例,保证线程安全。

4. 为什么需要 volatile

在没有 volatile 的情况下,可能会出现指令重排序问题:

  1. singleton = new Singleton(); 不是一个原子操作,实际上分为三步:
    • 分配内存。
    • 调用构造函数初始化对象。
    • 将对象引用赋值给 singleton
  2. 如果发生指令重排序,可能会导致以下情况:
    • 线程 A 执行了第 1 步和第 3 步,但尚未完成第 2 步。
    • 线程 B 访问到未完全初始化的对象,可能导致程序崩溃。
  3. 使用 volatile 可以禁止指令重排序,确保对象初始化的有序性。

5. 优点

  • 线程安全:通过双重检查和同步块,确保多线程环境下的安全性。
  • 性能优化:避免每次获取实例时都加锁,提升性能。
  • 延迟加载:实例在第一次使用时才会被创建,节省内存。

6. 缺点

  • 实现较复杂,容易出错。
  • 在某些情况下,可能会增加代码的维护成本。

7. 总结

这段代码是经典的双重检查锁定单例模式的实现,适用于多线程环境下的单例创建。通过 volatile 和双重检查机制,既保证了线程安全,又优化了性能,是一种高效的单例模式实现方式。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词