Java设计模式——单例模式(特性、各种实现、懒汉式、饿汉式、内部类实现、枚举方式、双重校验+锁)
文章目录
- 单例模式1️⃣
- 特性💪
- 单例模式的类型与实现:
- 类型
- 懒汉式实现(线程不安全)
- 懒汉式实现(线程安全)
- 双重锁校验懒汉式(线程安全)
- 饿汉式实现(线程安全)
- 使用类的内部类实现⭐
- 枚举方式实现单例(推荐)👍
单例模式1️⃣
单例模式是指在内存中只会创建且仅创建一次对象的设计模式。让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。
特性💪
- 唯一性:整个系统中,单例类只能有一个实例。
- 私有化构造函数:防止外部通过new关键字直接创建对象。
- 静态方法提供全局访问点:通常使用
getInstance()
方法来获取该类的唯一实例。 - 延迟实例化(懒加载):有些实现会在第一次调用
getInstance()
时才创建实例,以节省资源。
单例模式的类型与实现:
类型
- 懒汉式:在真正需要使用对象时才去创建该单例类对象
- 饿汉式:在类加载时已经创建好该单例对象,等待被程序使用
懒汉式实现(线程不安全)
只有当调用getInstance()
方法时才会创建单例对象,这种方式实现了延迟加载,但是需要考虑多线程环境下的线程安全问题。
public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
- 单例模式不允许外部直接创建,所以构造函数添加私有属性
private
- 这种方式满足懒汉式,但是在并发场景下,多个线程使用单例对象可能导致实例并存,从而违反了单例要求
懒汉式实现(线程安全)
上述懒汉式实现是线程不安全的(例如同时两个线程去获取单例对象,如果此时单例对象还未创建,可能会导致同事创建两个对象,从而违反单例),故我们要解决线程安全问题。
最容易想到的方法:使用锁(synchronized
)给类加锁来保证线程安全
public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
双重锁校验懒汉式(线程安全)
但是上述方法每次获取对象的时候都要去先获取锁,并发性能不是很好
可以进行优化:(如果没有实例化则加锁创建,如果实例化了则直接获取,可以使得已经实例化的单例对象在获取单例对象时无需先获取锁,而是直接获取对象)
使用Double Check(双重校验) + Lock(加锁) 的写法:
public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) { // 第一次检查,为了避免不必要的同步操作,提高性能。synchronized(Singleton.class) { if (instance == null) { // 第二次检查,以确保即使在多线程环境下也只创建一个实例。instance = new Singleton();}}}return instance;}
}
同时我们也使用了volatile
关键字去确保instance
变量的更新对所有线程都是立即可见的,并且禁止指令重排序,保证多线程环境下的正确性。
- 防止指令重排序: 在多线程环境下,JVM为了优化性能可能会对指令进行重排序。对于单例对象的创建而言,构造函数内部的操作可能被重排序到对象引用赋值之后。例如,如果一个线程正在执行实例化操作,它可能会先将对象引用设置为非空(即指向一块内存),然后再完成对象的初始化。这种情况下,另一个线程可能看到的是一个部分初始化的对象(因为对象的引用不是
null
了),这会导致不可预测的行为或错误。volatile
关键字可以禁止这种指令重排序,保证对象完全初始化之后才会被其他线程看到。 - 可见性保证:
volatile
关键字确保了一个线程对共享变量(在这个场景下是单例对象的引用)的修改对于其他线程是立即可见的。也就是说,当一个线程成功创建了单例对象后,所有其他线程都能看到这个对象已经被正确地初始化了,而不会读取到旧的或者默认的值(如null
)。这避免了多个线程同时创建多个实例的情况。
饿汉式实现(线程安全)
在类加载的时候就创建好单例对象,这种方式简单但不够灵活,因为它不能做到延迟加载。
public class Singleton{private static final Singleton singleton = new Singleton();private Singleton(){}public static Singleton getInstance() {return singleton;}
}
在类加载的时候,private static final Singleton singleton = new Singleton();
这行代码已经实例化好了一个单例对象在内存中。
使用类的内部类实现⭐
利用了Java语言的类加载机制,只有当调用getInstance()
方法时,内部类才会被加载,从而实现了懒加载和线程安全,同时不会因为加锁的方式耗费性能。
public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}
- 这主要是因为JVM虚拟机可以保证多线程并发访问的正确性,也就是一个类的构造方法在多线程环境下可以被正确的加载。
- 此种方式也是非常推荐使用的一种单例模式
枚举方式实现单例(推荐)👍
在Java中,使用枚举(Enum)来实现单例模式是一种非常简洁且高效的方法。枚举类型的单例不仅能够防止反射攻击和序列化导致的重复实例化问题,而且代码量极少,易于理解和维护。这是因为Java的枚举机制保证了每个枚举常量的唯一性,并且在类加载时自动初始化。
public enum Singleton {INSTANCE;private final String property;// 初始化属性值Singleton() {this.property = "Some Value";}public String getProperty() {return property;}// 其他业务方法public void doSomething() {// 方法逻辑...}
}public class Client {public static void main(String[] args) {Singleton singleton = Singleton.INSTANCE;singleton.doSomething();System.out.println(singleton.getProperty());}
}
枚举单例的优点:
- 天然线程安全:由于枚举常量在类加载时就被初始化,所以不需要额外的同步代码来保证线程安全。
- 防止反序列化创建新实例:枚举类型具有内在的序列化机制,如果尝试反序列化一个枚举类型的对象,它总是返回现有的枚举常量,而不会创建新的实例。
- 防止反射攻击:即使通过反射调用私有构造函数,也无法创建新的枚举实例。
- 简洁:相比于其他单例模式的实现方式,枚举单例的代码更加简洁明了。
- 延迟加载:虽然枚举类型不是天生支持懒加载,但是可以通过将实际的工作委托给另一个静态内部类来实现这一点。
相关文章:

Java设计模式——单例模式(特性、各种实现、懒汉式、饿汉式、内部类实现、枚举方式、双重校验+锁)
文章目录 单例模式1️⃣特性💪单例模式的类型与实现:类型懒汉式实现(线程不安全)懒汉式实现(线程安全)双重锁校验懒汉式(线程安全)饿汉式实现(线程安全)使用类的内部类实现⭐枚举方式实现单例(推荐)👍 单例…...

数字普惠金融对新质生产力的影响研究(2015-2023年)
基于2015—2023年中国制造业上市公司数据,探讨了数字普惠金融对制造业企业新质生产力的影响及作用机理。研究发现,数字普惠金融有助于促进制造业企业新质生产力的发展,尤其是在数字普惠金融的使用深度较大的情况下,其对新质生产力…...

国产编辑器EverEdit - 扩展脚本:新建同类型文件(避免编程学习者反复新建保存练习文件)
1 扩展脚本:在当前文件目录下新建同类型文件 1.1 应用场景 用户在进行编程语言学习时,比如:Python,经常做完一个小练习后,又需要新建一个文件,在新建文件的时候,不但要选择文件类型,…...

jupyter notebook练手项目:线性回归——学习时间与成绩的关系
线性回归——学习时间与学习成绩的关系 第1步:导入工具库 pandas——数据分析库,提供了数据结构(如DataFrame和Series)和数据操作方法,方便对数据集进行读取、清洗、转换等操作。 matplotlib——绘图库,p…...

dockerfile2.0
dockerfile实现lnmp nginx centos7 mysql centos7 php centos7 自定义镜像来实现整个架构 cd /opt mkdir nginx mysql php cd nginx 拖入nginx和wordpress vim Dockerfile vim nginx.conf ↓ worker_processes 1; events {worker_connections 1024; } http {include …...

【spring mvc】文件上传、下载
文件上传,存储至本地目录中 一、代码1、工具类(敏感后缀过滤)2、文件上传,存储至本地3、文件下载 二、效果演示1、上传1.1、postMan 请求1.2、上传效果 2、下载2.1、下载效果 一、代码 1、工具类(敏感后缀过滤&#x…...

FPGA工程师成长四阶段
朋友,你有入行三年、五年、十年的职业规划吗?你知道你所做的岗位未来该如何成长吗? FPGA行业的发展近几年是蓬勃发展,有越来越多的人才想要或已经踏进了FPGA行业的大门。很多同学在入行FPGA之前,都会抱着满腹对职业发…...
java fastjson2 解析JSON用法解析
Fastjson2 是 Fastjson 的升级版本,提供了更好的性能和扩展性,同时也在 API 和功能上做了很多改进。使用 Fastjson2 解析 JSON 数据非常简单,支持多种方式来解析 JSON 字符串、嵌套 JSON 对象和数组、以及转换成 Java 对象。下面详细介绍 Fas…...

计算机视觉算法实战——步态识别(主页有源码)
✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ 1. 步态识别简介✨✨ 步态识别(Gait Recognition)是计算机视觉领域中的一个…...

LabVIEW水位监控系统
LabVIEW开发智能水位监控系统通过集成先进的传感技术与控制算法,为工业液体存储提供精确的水位调控,保证了生产过程的连续性与安全性。 项目背景 在化工和饮料生产等行业中,水位控制的准确性对保证生产安全和提高产品质量至关重要。传统的水…...

网络层协议-----IP协议
目录 1.认识IP地址 2.IP地址的分类 3.子网划分 4.公网IP和私网IP 5.IP协议 6.如何解决IP地址不够用 1.认识IP地址 IP 地址(Internet Protocol Address)是指互联网协议地址。 它是分配给连接到互联网的设备(如计算机、服务器、智能手机…...
计算机网络八股文学习笔记
总结来自于javaguide,本文章仅供个人学习复习 javaguide计算机网络八股 文章目录 计算机网络基础网络分层模型OSI七层模型TCP/IP四层模型 HTTP从输入URL到页面展示到底发生了什么?(非常重要)HTTP状态码HTTP Header中常见的字段有哪些?HTTP和HTTPS有什么区别?(重要)HTTP/1.0和…...

IntelliJ IDEA中Maven项目的配置、创建与导入全攻略
大家好,我是袁庭新。 IntelliJ IDEA是当前最流行的Java IDE(集成开发环境)之一,也是业界公认最好用的Java开发工具之一。IntelliJ IDEA支持Maven的全部功能,通过它我们可以很轻松地实现创建Maven项目、导入Maven项目、…...

如何在Jupyter中快速切换Anaconda里不同的虚拟环境
目录 介绍 操作步骤 1. 选择环境,安装内核 2. 注册内核 3. 完工。 视频教程 介绍 很多网友在使用Jupyter的时候会遇到各种各样的问题,其中一个比较麻烦的问题就是我在Anaconda有多个Python的环境里面,如何让jupyter快速切换不同的Pyt…...

stack和queue专题
文章目录 stack最小栈题目解析代码 栈的压入弹出序列题目解析代码 queue二叉树的层序遍历题目解析代码 stack stack和queue都是空间适配器 最小栈 最小栈的题目链接 题目解析 minst是空就进栈,或者是val < minst.top()就进栈 代码 class MinStack { public:M…...

【Vue】点击侧边导航栏,右侧main对应显示
需求:点击侧边导航栏,右侧main对应显示 通过v-if或v-show等指令来控制不同内容的显示隐藏来实现 注意: 使用v-if时候进行导航栏切换,右侧显示区域可能会出现样式错乱;使用v-show则不会出现此错误 <template>&…...
【Debug】django.db.utils.OperationalError: (1040, ‘Too many connections‘)
报错: django.db.utils.OperationalError: (1040, ‘Too many connections‘) 排查 可能是Mysql的连接数量超过了允许的最大连接数量; 查看Mysql允许最大连接数量: -- 查看允许连接的最大数量 SHOW VARIABLES LIKE %max_connections%;-- 查…...
如何开放2375和2376端口供Docker daemon监听
Linux (以 Ubuntu 为例) 1. 修改 Docker 配置文件 打开 Docker 的配置文件 /etc/docker/daemon.json。如果该文件不存在,则可以创建一个新的。 bash sudo nano /etc/docker/daemon.json在配置文件中添加以下内容: json {"hosts": ["un…...

RabbitMQ确保消息可靠性
消息丢失的可能性 支付服务先扣减余额和更新支付状态(这俩是同步调用),然后通过RabbitMq异步调用支付服务更新订单状态。但是有些情况下,可能订单已经支付 ,但是更新订单状态却失败了,这就出现了消息丢失。…...
前端常见的设计模式之【单例模式】
前端常见的设计模式: 单例模式观察者模式工厂模式适配器模式装饰器模式命令模式迭代器模式组合模式策略模式发布订阅模式 单例模式【创建型设计模式】: 单例模式是确保一个类只有一个实例,并提供一个全局访问点。这个模式非常适合那些需要…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...