当前位置: 首页 > news >正文

单例设计模式之懒汉式以及线程安全问题

在单例设计模式中,懒汉式(Lazy Initialization) 通过延迟实例化来优化资源使用,但在多线程环境下存在线程安全问题。以下是其核心问题及解决方案的详细解析:


一、基础懒汉式代码(线程不安全)

public class Singleton {private static Singleton instance;private Singleton() {} // 私有构造器public static Singleton getInstance() {if (instance == null) {         // 步骤1:检查实例是否存在instance = new Singleton(); // 步骤2:创建实例}return instance;}
}
问题分析

当多个线程同时调用 getInstance() 时:

  1. 线程A 进入步骤1,发现 instance 为 null

  2. 线程B 同时进入步骤1,同样发现 instance 为 null

  3. 两个线程都会执行步骤2,创建多个实例,违反单例原则。


二、解决方案

1. 同步方法(线程安全,效率低)

public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;
}
  • 优点:简单直接,确保线程安全。

  • 缺点:每次调用 getInstance() 都需要同步,性能差(99% 情况下实例已存在,无需同步)。


2. 双重检查锁(Double-Check Locking,DCL)

public class Singleton {private static volatile Singleton instance; // volatile 禁止指令重排序private Singleton() {}public static Singleton getInstance() {if (instance == null) {                  // 第一次检查(无锁)synchronized (Singleton.class) {     // 加锁if (instance == null) {          // 第二次检查(有锁)instance = new Singleton();  // 创建实例}}}return instance;}
}
关键点
  • 双重检查:减少锁竞争,只有第一次创建实例时同步。

  • volatile 关键字:禁止 JVM 指令重排序,防止返回未初始化完成的实例。

    • instance = new Singleton() 的代码实际分为三步:

      1. 分配内存空间。

      2. 初始化对象。

      3. 将 instance 指向分配的内存。

    • 若无 volatile,可能发生指令重排(步骤3在步骤2之前执行),导致其他线程获取到未初始化的实例。


3. 静态内部类(推荐)

public class Singleton {private Singleton() {}private static class Holder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return Holder.INSTANCE; // 类加载时初始化实例}
}
原理
  • JVM 在加载外部类时不会加载内部类,只有调用 getInstance() 时才会加载 Holder 类。

  • 类加载过程是线程安全的,由 JVM 保证,天然避免多线程问题。


4. 枚举实现(最佳实践)

public enum Singleton {INSTANCE; // 单例实例public void doSomething() {// 业务方法}
}
优点
  • 线程安全由 JVM 保证。

  • 防止反射攻击(无法通过反射创建枚举实例)。

  • 防止反序列化生成新对象。


三、方案对比

方案线程安全性能实现复杂度防反射/反序列化
同步方法
双重检查锁
静态内部类
枚举

四、总结

  • 基础懒汉式:多线程下不安全,需改进。

  • 同步方法:简单但性能差,不推荐高并发场景。

  • 双重检查锁:性能优,需配合 volatile

  • 静态内部类:推荐方案,兼顾安全与性能。

  • 枚举:最佳实践,支持防反射和反序列化。

http://www.xdnf.cn/news/155701.html

相关文章:

  • 【计算机视觉】CV项目实战- 深度解析TorchVision_Maskrcnn:基于PyTorch的实例分割实战指南
  • 从“拼凑”到“构建”:大语言模型系统设计指南!
  • 【Vue】Vue3项目创建
  • 美团Java后端二面面经!
  • 【数论分块】数论分块算法模板及真题
  • # 家庭网络IPv6地址的一些知识
  • 思科路由器重分发(静态路由+OSPF动态路由+RIP动态路由)
  • 基于MTF的1D-2D-CNN-BiLSTM-Attention时序图像多模态融合的故障分类识别(Matlab完整源码和数据),适合研究学习,附模型研究报告
  • Leetcode刷题 由浅入深之哈希法——454. 四数相加Ⅱ
  • Logi Options+ 的 Flow:端口信息
  • 驱动开发(1)|鲁班猫rk356x内核编译,及helloworld驱动程序编译
  • 微信小程序核心技术栈
  • ORACLE数据库备份入门:第四部分:2-备份场景举例
  • 计算机视觉——对比YOLOv12、YOLOv11、和基于Darknet的YOLOv7的微调对比
  • MyBatis 官方子项目详细说明及表格总结
  • JavaScript基础知识合集笔记1——数据类型
  • TDengine 中的压缩设计
  • 毕业项目-Web入侵检测系统
  • 关于TCP三次握手和四次挥手的疑点
  • 游戏状态管理:用Pygame实现场景切换与暂停功能
  • Unity-Shader详解-其一
  • MySQL多查询条件下深度分页性能优化技巧及示例总结
  • Pytorch(无CPU搭建)+Jupyter
  • Unity-Shader详解-其二
  • 【WLAN】华为无线AC双机热备负载分担—双链路热备份
  • 【数据融合】基于拓展卡尔曼滤波实现雷达与红外的异步融合附matlab代码
  • C++异步并发支持库future
  • 探针台的具体分类有哪些
  • 基于pandoc的MarkDown格式与word相互转换小工具开发(pyqt5)
  • AAAI2016论文 UCO: A Unified Cybersecurity Ontology