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

在单例设计模式中,懒汉式(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.mzph.cn/bicheng/78983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows7升级PowerShell到5.1

window7系统,安装了vs2019后,应用要用到PowerShell,Tool->Commond Line->Developer PowerShell时,提示版本需要3.0以上。还有编译新版本vcpkg(2021前的版本),脚本报错。所以需要升级下Pow…

区块链:去中心化应用(DApp)开发全流程解析

一、DApp的核心概念与特点 去中心化应用(DApp)是一种基于区块链技术的应用程序,其核心逻辑通过智能合约在链上执行,数据存储和交互均不依赖中心化服务器。相比传统应用,DApp具备以下特点: 去中心化&#x…

跟我学C++中级篇——控制死锁

一、同步和死锁 在前面学习多线程和网络编程时,都对线程中数据的同步和数据结构多线程访问的安全问题进行了分析和说明。其实,多线程编程之所以难,难点之一就在这里,数据同步意味着效率和安全的平衡,而这里的安全有一…

【matlab】绘制maxENT模型的ROC曲线和omission curve

文章目录 一、maxENT模型二、ROC曲线三、实操3.1 数据提取3.2 绘制ROC曲线3.3 绘制遗漏曲线3.4 多次训练的ROC和测试的ROC 一、maxENT模型 前面的文章已经详细讲过了。 maxENT软件运行后,会生成一个html报告,里面有ROC曲线,但我们往往需要自…

nginx 核心功能

目录 一、基于授权的访问控制 1. 使用 htpasswd 生成用户认证文件 2. 修改 Nginx 主配置文件 二、基于客户端的访问控制 三、Nginx 虚拟主机 1. 基于域名的虚拟主机 2. 基于 IP 的虚拟主机 3. 基于端口的虚拟主机 四、LNMP 架构部署及应用 1. 安装 MariaDB 2. 安装并…

mongoose插入文档,字段类型, 字段验证, 删除文档,更新文档,读取文档,查询文档的条件控制 ,字段筛选,数据排序,数据截取

、Mongoose 中与 文档操作(插入、查询、更新、删除)及其相关功能(字段类型、验证、条件筛选、排序、分页等)相关示例: 📋 一、字段类型定义(Schema Types) const mongoose require…

类和对象 (拷贝构造函数和运算符重载)上

类和对象 (拷贝构造函数和运算符重载)上 拷贝构造函数存在的原因及解决的 C 语言问题 1. 浅拷贝带来的问题 在 C 语言里,当对结构体或者数组进行拷贝操作时,执行的是浅拷贝。所谓浅拷贝,就是单纯地把一个对象的所有成员变量的值复制到另一…

Python深度挖掘:openpyxl和pandas的使用详细

文章目录 一、Excel处理在数据分析中的重要性二、openpyxl基础与核心功能2.1 openpyxl简介与安装2.2 工作簿与工作表的基本操作创建新工作簿打开已有工作簿工作表操作 2.3 单元格操作详解基本单元格操作批量操作单元格特殊单元格操作 2.4 样式与格式设置字体样式对齐方式边框设…

Android Q允许低内存启用系统弹窗

如果SYSTEM_ALERT_WINDOW权限可用,则返回true。 *从Q开始,在低ram手机上禁用SYSTEM_ALERT_WINDOW。 vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/Utils.java public static boolean isSystemAlertWindowEnabled(Co…

taro小程序如何实现大文件(视频、图片)后台下载功能?

一、需求背景 1、需要实现小程序下载最大500M视频 2、同时需支持图片下载 3、退到其他页面再次回到当前页面时,下载进度也需要展示 二、实现步骤 1、在app.ts文件定义一个全局变量globalDownLoadData 2、写一个独立的下载hooks,代码如下(…

BUUCTF——Online Tool

BUUCTF——Online Tool 进入靶场 <?phpif (isset($_SERVER[HTTP_X_FORWARDED_FOR])) {$_SERVER[REMOTE_ADDR] $_SERVER[HTTP_X_FORWARDED_FOR]; }if(!isset($_GET[host])) {highlight_file(__FILE__); } else {$host $_GET[host];$host escapeshellarg($host);$host e…

《解锁CSS Flex布局:重塑现代网页布局的底层逻辑》

网页布局作为用户体验的基石&#xff0c;其重要性不言而喻。从早期简单的表格布局&#xff0c;到后来基于浮动与定位的复杂尝试&#xff0c;网页布局技术始终在不断演进。而CSS Flex布局的出现&#xff0c;宛如一颗璀璨的新星&#xff0c;彻底革新了网页布局的设计理念与实践方…

4.28-4.29 Vue

基于数据渲染出用户看到的页面。 常用指令&#xff1a; click单击事件。 axios&#xff1a; 发出请求后&#xff0c;不会等待请求结束&#xff0c;而是继续进行下面的代码。

每日算法-250429

每日 LeetCode 题解 (2025-04-29) 大家好&#xff01;这是今天的 LeetCode 刷题记录&#xff0c;主要涉及几道可以使用贪心策略解决的问题。 2037. 使每位学生都有座位的最少移动次数 题目描述: 思路 贪心 解题过程 要使总移动次数最少&#xff0c;直观的想法是让每个学生…

yolov8+kalman 实现目标跟踪统计人流量

简述 最近接了毕业生的毕业设计题&#xff0c;想着帮帮忙&#xff0c;要使用机器视觉识别&#xff0c;追踪和逻辑统计的方式来统计人流&#xff0c;要求是满足下面特性 高精度&#xff1a;YOLOv8 提供高质量检测&#xff0c;卡尔曼滤波平滑跟踪。高效率&#xff1a;两者结合满…

Shopify网上商店GraphQL Admin接口查询实战

目录 一、Shopify网上商店 二、个人商店配置接口权限 三、PostMan调用接口测试 四、通过Java服务调用接口 一、Shopify网上商店 Shopify是由Tobi Ltke创办的加拿大电子商务软件开发商&#xff0c;总部位于加拿大首都渥太华&#xff0c;已从一家在咖啡店办公的 5人团队&…

【Tips】高效文献管理:Zotero 导入参考文献的多种方式详解

高效文献管理&#xff1a;Zotero 导入参考文献的多种方式详解 在学术研究中&#xff0c;高效管理参考文献是提升效率的关键。Zotero 作为一款强大的文献管理工具&#xff0c;提供了多种便捷的文献导入方式。以下结合文献题录完整性对比分析&#xff0c;为大家详细介绍 Zotero …

[AI]browser-use + web-ui 大模型实现自动操作浏览器

[AI]browser-use web-ui 大模型实现自动操作浏览器 介绍 官方地址&#xff1a;https://github.com/browser-use/web-ui browser-use主要作用是将 AI Agent 与浏览器链接起来从而实现由 AI 驱动的浏览器自动化。今天会给大家介绍如何通过browser-use web-ui来搭建并操作browse…

Springboot请求静态资源时,request.getServletPath() 返回error

大家好&#xff0c;我是 程序员码递夫。 SpringBoot请求静态资源时&#xff0c;request.getServletPath() 返回error&#xff0c; 明明我的目录文件是存在的怎么就报错了呢&#xff1f; 如我请求 http://127.0.0.1:9090/Hanfu/upload/1647161536390.png 通常是因为请求的资…

在开发板上如何处理curl: (60) SSL certificate problem

目录 引言 问题解析 解决方法 跳过证书验证 采用证书认证 结语 引言 最近一直推荐学生们在课程实验中使用curl及其libcurl。curl 是一个强大的命令行工具&#xff0c;用于在命令行中进行数据传输。它支持多种协议&#xff0c;如 HTTP、HTTPS、FTP、FTPS、SCP、SFTP 等。…