当前位置: 首页 > 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

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

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

相关文章:

  • 从循环角度分析逐位分离法
  • 【人工智能之大模型】详述大模型中流水线并行(Pipeline Parallelism)的​GPipe推理框架?
  • 如何选择合适的探针台
  • C#中wpf程序中的x名空间详解
  • 微信小程序 template 模版详解
  • 机器学习之二:指导式学习
  • 精益数据分析(27/126):剖析用户价值与商业模式拼图
  • 有源晶振与无源晶振详解:区别、应用与选型指南
  • 电子电器架构 --- 乘用车电气/电子架构开发的关键挑战与应对策略
  • SQL 查询进阶:WHERE 子句与连接查询详解
  • 【高频考点精讲】前端职业发展:如何规划前端工程师的成长路径?
  • PCL绘制点云+法线
  • 【教程】Windows通过网线共享网络给其它设备
  • python调用ffmpeg对截取视频片段,可批量处理
  • 介绍常用的退烧与消炎药
  • 前端学习笔记(四)自定义组件控制自己的css
  • 写了一个关于SpringAop记录用户操作的功能
  • 从入门到精通汇编语言 第七章(高级汇编语言技术)
  • goweb项目结构以及如何实现前后端交互
  • 【GoChat】密码处理与实现JWT+进行功能单测
  • 葛兰西:“生活就是抵抗”
  • 别让心脏“饿肚子”,心肌缺血全解析
  • 六部门:进一步优化离境退税政策扩大入境消费
  • 中公教育:去年全面扭亏,经营性现金流增长169.6%
  • 泽连斯基与特朗普进行简短会谈
  • 政治局会议深度|提出“设立新型政策性金融工具”有何深意?