单例设计模式之懒汉式以及线程安全问题
在单例设计模式中,懒汉式(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()
时:
-
线程A 进入步骤1,发现
instance
为null
。 -
线程B 同时进入步骤1,同样发现
instance
为null
。 -
两个线程都会执行步骤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()
的代码实际分为三步:-
分配内存空间。
-
初始化对象。
-
将
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
。 -
静态内部类:推荐方案,兼顾安全与性能。
-
枚举:最佳实践,支持防反射和反序列化。
相关文章:
单例设计模式之懒汉式以及线程安全问题
在单例设计模式中,懒汉式(Lazy Initialization) 通过延迟实例化来优化资源使用,但在多线程环境下存在线程安全问题。以下是其核心问题及解决方案的详细解析: 一、基础懒汉式代码(线程不安全) pu…...

今日头条如何查看IP归属地?详细教程与常见问题解答
在当今互联网时代,IP属地信息已成为各大社交平台展示用户真实性的重要标识。今日头条作为国内领先的资讯平台,也提供了IP属地显示功能。那么,今日头条怎么查看IP归属地?本文将详细介绍在今日头条11.9.0版本中如何查看自己和他人的…...
React-Hook
一、基础 Hooks 1、useState - 状态管理 useState 是 React 提供的一个函数,用来在函数组件中声明和修改状态,没有它,函数组件只是一个“静态模板”;有了它,函数组件可以保存和更新数据(比如计数器数值、输…...
前端节流、防抖函数
节流 什么是节流? 节流就是同一个事件 一秒钟他执行了很多次。但是我不想他执行这么多次,我只想让他执行一次 或者两次。 那该怎么办? why baby why 那我想就是他执行的时候 我就设置一个定时器,如果定时器是空的,等会…...
高级java每日一道面试题-2025年4月26日-基础篇[反射篇]-什么是类型擦除?它与反射之间有什么关系?
如果有遗漏,评论区告诉我进行补充 面试官: 什么是类型擦除?它与反射之间有什么关系? 我回答: 类型擦除与反射的深度解析 一、类型擦除(Type Erasure) 类型擦除是Java泛型实现的核心机制,旨在通过编译期处理确保向…...
Centos7系统防火墙使用教程
CentOS 7是一种常见的Linux操作系统,防火墙作为网络安全的第一道防线,对于服务器的安全至关重要。本文将介绍CentOS 7系统中防火墙的使用教程,包括如何开启、关闭、配置以及防火墙规则的添加和删除。 一、查看防火墙状态 在开始操作之前&am…...
缓存与数据库数据一致性:旁路缓存、读写穿透和异步写入模式解析
旁路缓存模式、读写穿透模式和异步缓存写入模式是三种常见的缓存使用模式,以下是对三种经典缓存使用模式在缓存与数据库数据一致性方面更全面的分析: 一、旁路缓存模式(Cache - Aside Pattern) 1.数据读取流程 应用程序首先向缓…...

【物联网】基于LORA组网的远程环境监测系统设计(机智云版)
基于LORA组网的远程环境监测系统设计(机智云版) 演示视频: 简介: 1.本系统有一个主机,两个从机。 2.一主多从的LORA组网通信,主机和两个从机都配备了STM32F103单片机与 LoRa 模块,主机作为中心设备及WIFI网关,负责接收和发送数据到远程物联网平台和手机APP,两个从机…...
Pygame事件处理详解:键盘、鼠标与自定义事件
Pygame事件处理详解:键盘、鼠标与自定义事件 在游戏开发中,玩家的交互是至关重要的。无论是移动角色、触发动作还是暂停游戏,都需要通过各种输入来实现。Pygame作为一个功能强大的Python库,提供了丰富的API来处理这些输入,包括键盘、鼠标以及自定义事件。本文将详细介绍如…...

制作一款打飞机游戏22:表格导出
编辑器功能扩展 今天,我想让编辑器能够处理一个数组,这是编辑器将要编辑的东西,它只编辑数组。这些区域在后续的不同版本的编辑器中会有不同的含义,但现在我想创建一个模板,能够加载一个二维数组,并将二维…...

Linux内核源码结构
目录 Linux内核源码结构 Linux内核版本命名 Linux内核版本选择 内核源码结构 arch:与CPU架构相关的源代码 block:磁盘设备的支持 COPYING文件 CREDITS文件 crypto:加密相关 Documentation: drivers:设备驱动 firmware:固件 fs:文件系统 include:头文件…...

72.评论日记
【巫师】中美关税战02:应给人民爆装备,以及普通人如何应对(7条建议)_哔哩哔哩_bilibili 2025年4月26日11:03:31...
在springboot项目中,如何进行excel表格的导入导出功能?
以下是使用 Apache POI 和 EasyExcel 实现 Excel 表格导入导出功能的具体代码示例。 1. 使用 Apache POI 实现 Excel 导入导出 添加依赖 在 pom.xml 中添加 Apache POI 的依赖: <dependency><groupId>org.apache.poi</groupId><artifactId…...

Websocket自动发送消息客户端工具
点击下载《Websocket自动发送消息客户端工具》 1. 前言 在现代网络应用中,实时通信和即时数据传输变得越来越重要。WebSocket作为一种全双工通信协议,因其高效、实时的特点,被广泛应用于聊天应用、实时数据监控、在线游戏等领域。然而&…...

STM32的开发环境介绍
目录 STM32软件环境 Keil软件在线安装 其他软件环境安装 STM32开发的几种方式 STM32寄存器版本和库函数版本 标准外设库的作用: STM32软件环境 STM32 的集成开发环境(IDE):编辑编译软件 常见的环境: (1)KEIL&a…...

数据库系统概论(四)关系操作,关系完整性与关系代数
数据库系统概论(四)详细讲解关系操作,关系完整性与关系代数 前言一、什么是关系操作1.1 基本的关系操作1.2 关系数据语言的分类有哪些 二、关系的完整性2.1 实体完整性2.2 参照完整性2.3 用户的定义完整性 三、关系代数是什么3.1 传统的集合运…...

基于 IPMI + Kickstart + Jenkins 的 OS 自动化安装
Author:Arsen Date:2025/04/26 目录 环境要求实现步骤自定义 ISO安装 ipmitool安装 NFS定义 ks.cfg安装 HTTP编写 Pipeline 功能验证 环境要求 目标服务器支持 IPMI / Redfish 远程管理(如 DELL iDRAC、HPE iLO、华为 iBMC)&…...
【AI提示词】财务顾问
提示说明 财务顾问是一个专注于帮助个人和企业优化财务状况、制定财务计划并实现财务目标的专业人士。 提示词 # Role: 财务顾问## Profile - language: 中文 - description: 财务顾问是一个专注于帮助个人和企业优化财务状况、制定财务计划并实现财务目标的专业人士。 - ba…...

使用 Node、Express 和 MongoDB 构建一个项目工程
本文将详细介绍如何使用 Node.js Express MongoDB 构建一个完整的 RESTful API 后端项目,涵盖: 项目初始化 Express 服务器搭建 MongoDB 数据库连接 REST API 设计(CRUD 操作) 错误处理与中间件 源码结构与完整代码 部署建…...

【C++11】右值引用和移动语义:万字总结
📝前言: 这篇文章我们来讲讲右值引用和移动语义 🎬个人简介:努力学习ing 📋个人专栏:C学习笔记 🎀CSDN主页 愚润求学 🌄其他专栏:C语言入门基础,python入门基…...
【滑动窗口+哈希表/数组记录】Leetcode 3. 无重复字符的最长子串
题目要求 给定一个字符串 s,找出其中不含有重复字符的最长子串的长度。 子字符串是字符串中连续非空字符序列。 示例 1 输入:s "abcabcbb" 输出:3 解释:无重复字符的最长子串是 "abc",长度为…...
pytest 技术总结
目录 一 pytest的安装: 二 pytest有三种启动方式: 三 用例规则: 四 配置框架: 一 pytest的安装: pip install pytest # 安装 pip install pytest -U # 升级到最新版 二 pytest有三种启动方式: 1…...
java中的Selector详解
Selector(选择器)是Java NIO(非阻塞I/O)的核心组件,用于实现I/O多路复用,允许单个线程管理多个通道(Channel),从而高效处理高并发场景。 一、Selector的核心概念与作用 I/O多路复用 Selector通过事件驱动机制,监听多个通道的就绪状态(如可读、可写、连接建立等),无…...
DeepSeek 的长上下文扩展机制
DeepSeek 在基础预训练完成后,引入 YaRN(Yet another RoPE extensioN method)技术,通过额外的训练阶段将模型的上下文窗口从默认的 4K 逐步扩展至 128K。整个过程分为两个阶段:第一阶段将上下文窗口从 4K 扩展到 32K;第二阶段则进一步从 32K 扩展到 128K。每个阶段均采用…...
【修复】Django收到请求报Json解析错误
Django收到请求报Json解析错误 场景分析解决 场景 在使用Postman发送Django的请求时,只能使用原来的json内容,如果修改json内容则会报json解析上的错误 分析 可能是有对请求内容的长度做了上报校验 解决 最终在请求头Headers里找到了Content-Length…...
openEuler对比CentOS的核心优势分析
openEuler对比CentOS的核心优势分析 在开源操作系统领域,openEuler与CentOS均占据重要地位,但随着CentOS维护策略的调整(如CentOS 8停止维护,转向CentOS Stream),越来越多的用户开始关注国产化替代方案。o…...

Python基于Django的全国二手房可视化分析系统【附源码】
博主介绍:✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&…...

VulnHub-DC-2靶机渗透教程
VulnHub-DC-2靶机渗透教程 1.靶机部署 [Onepanda] Mik1ysomething 靶机下载:https://download.vulnhub.com/dc/DC-2.zip 直接使用VMware导入打开就行 2.信息收集 2.1 获取靶机ip(arp-scan/nmap) arp-scan -l nmap 192.168.135.0/24 2.2 详细信息扫描(nmap)…...

n8n 中文系列教程_10. 解析n8n中的AI节点:从基础使用到高级Agent开发
在自动化工作流中集成AI能力已成为提升效率的关键。n8n通过内置的LangChain节点,让开发者无需复杂代码即可快速接入GPT-4、Claude等大模型,实现文本处理、智能决策等高级功能。本文将深入解析n8n的AI节点体系,从基础的Basic LLM Chain到强大的…...
Jest 快照测试
以下是关于 Jest 快照测试的系统化知识总结,从基础使用到底层原理全面覆盖: 一、快照测试核心原理 1. 工作机制三阶段 #mermaid-svg-GC46t2NBvGv7RF0M {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GC46t2NBvGv…...