Java:单例模式(Singleton Pattern)及实现方式

一、单例模式的概念

单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点来访问该实例,是 Java 中最简单的设计模式之一。该模式常用于需要全局唯一实例的场景,例如日志记录器、配置管理、线程池、数据库连接池等。

注意:单例模式的构造方法必须要声明为private类型。

欢迎关注工 众号:ItBeeCoder,查看更多高质量技术文章,发送“后端”获取资料

二、实现方式

在Java中,单例模式有多种实现方式,每种方式都有其适用场景和优缺点。下面主要从每种方式的特点、Java代码实现方式及优缺点三个方面介绍几种常见的实现方式。

1.饿汉式(Eager Initialization)

1)特点

类加载时立即创建并初始化实例,是线程安全的,但由于有些类的实例并不会立即用到,这种方式可能会浪费资源,尤其是创建占用资源较多的大对象时,尤为明显。

2)代码实现

public class EagerSingleton {// 类加载时直接创建实例private static final EagerSingleton instance = new EagerSingleton();// 私有构造函数防止外部实例化,这里构造函数必须为私有的private EagerSingleton() {}public static EagerSingleton getInstance() {return instance;}
}

3)优缺点
使用这种方式创建单个示例的优缺点都比较明显。
优点:简单、线程安全。
缺点:实例在类加载时创建,若从未使用会导致资源浪费。

对于计算机技术感兴趣的读者,可以加入下裙,和更多行业爱好者分享、交流最新的技术。

在这里插入图片描述

2. 同步方法懒汉式(Lazy)(线程安全,性能差)

1)特点
这种方法通过在实例创建方法getInstance()前加synchronized关键字保证多线程环境下只能创建一个实例对象,这种方法保证线程安全,但性能较低(使用了synchronized 关键字,会导致操作系统用户态和内核态的切换,耗费时间和性能,深层原因后面会在介绍synchronized 关键字的文章里详细介绍)。

2)代码实现

public class SynchronizedSingleton {private static SynchronizedSingleton instance;private SynchronizedSingleton() {}public static synchronized SynchronizedSingleton getInstance() {if (instance == null) {instance = new SynchronizedSingleton();}return instance;}
}

3)优缺点
优点:这种方法是线程安全的,synchronized关键字保证多线程环境下只能创建一个实例对象。
缺点:每次调用getInstance()都需要同步,性能差。

欢迎关注工 众号:ItBeeCoder,查看更多高质量技术文章,发送“后端”获取资料

3. 懒汉式(Lazy Initialization,不推荐,了解即可)

1)特点

该种实现方式延迟初始化实例对象,存在多线程安全问题。

2)代码实现

public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {Aif (instance == null) {B)      instance = new LazySingleton();}return instance;}
}

3)优缺点
优点:延迟加载,节省资源。
缺点:这里instance实例前未加volatile关键字,并且getInstance()方法未加同步关键字或者加锁,这种方法是非线程安全的,多线程环境下可能创建多个实例。

例如:有两个线程a和b同时要创建LazySingleton 类的实例对象,a、b线程执行到 A) 处时,满足if中的判断条件,就会创建一个LazySingleton 类的实例对象。b线程这时也满足if条件,同样会创建一个实例,所以这种方法并不能保证多线程环境下只创建一个对象。

笔者注:这种方式建议了解即可,真正项目中不要用这种方式。

4. 双重检查锁定(Double-Checked Locking,DCL,推荐该种方法)

1)特点
减少同步次数,兼顾性能与线程安全。
欢迎关注工 众号:ItBeeCoder,查看更多高质量技术文章,发送“后端”获取资料

2)代码实现

public class DCLSingleton {// 这里使用volatile的作用是禁止指令重排序,因为JAVA中创建对象包括几步:如果不使用volatile,private static volatile DCLSingleton instance;private DCLSingleton() {}public static DCLSingleton getInstance() {Aif (instance == null) { // 第一次检查Bsynchronized (DCLSingleton.class) {Cif (instance == null) { // 第二次检查D)             instance = new DCLSingleton();}}}return instance;}
}

3)优缺点
优点:这种方法是线程安全的,并且在真正用到对象的时候,才会进行对象的创建(懒汉式,延迟创建),避免了提前创建对象导致的资源浪费,性能较好。
缺点:volatile关键在JDK 1.5及以后的版本才支持,JDK1.5以前的版本并不支持该种写法,需要注意,另外代码实现方式稍微复杂一些。

4)该方法使用Volatile关键字的原因
假设当前有两个线程1和2都要获取DCLSingleton 类的实例,线程1执行到A)处,满足条件进入到if判断中,接着进入到同步代码块,执行到B)行代码后,线程1的CPU执行时间片用完,让出CPU,线程2开始执行,线程2满足A)、C)处的判断条件,一直执行到D)处,并开始创建对象。Java中对象的创建主要分为几个步骤:1)声明一个引用变量(值为null);2)创建对象并为对象分配内存空间;3)初始化对象4)将对象的内存地址赋给引用变量。JVM在执行代码指令时,会根据情况对指令进行重排序。如果JVM将创建对象的指令重排序为2)、3)、1)、4),线程2执行完2)和3)后时间片用完,这些对象的引用仍为NULL。线程1)接着执行,会重新创建一个对象。最终导致多线程环境下创建多个实例。

volatile关键字可以防止指令重排序,所以这里在instance实例声明前加了该关键字,创建对象的时候会完全按照1)、2)、3)、4)的步骤执行,避免多线程环境下线程不安全的问题。

5. 静态内部类(Holder模式)

1)特点
利用类加载机制保证线程安全,延迟加载且无需同步。

2)代码实现

public class HolderSingleton {private HolderSingleton() {}// 静态内部类持有实例private static class Holder {private static final HolderSingleton INSTANCE = new HolderSingleton();}public static HolderSingleton getInstance() {return Holder.INSTANCE;}
}

3)优缺点
优点:线程安全、延迟加载、无同步开销。
缺点:无法传递参数初始化实例。

6. 枚举(Enum)

1)特点
枚举是最简洁、安全的单例实现方式,天然防反射和序列化破坏。

2)代码实现

public enum EnumSingleton {INSTANCE; // 单例实例// 添加其它业务方法public void doSomething() {System.out.println("Singleton method");
// 其它业务代码}
}

3)优缺点
优点:线程安全、防止反射攻击、自动处理序列化。
缺点:无法继承其他类(枚举类已继承Enum)。

Java中单例模式有多种实现方式,包括饿汉式、懒汉式、同步方法懒汉式、双重检查锁定、静态内部类和枚举。每种方式都有其优缺点和适用场景:饿汉式简单但可能浪费资源;懒汉式延迟加载但非线程安全;同步方法懒汉式线程安全但性能低;双重检查锁定和静态内部类都提供了线程安全和延迟加载的解决方案;枚举是最简洁安全的单例实现,防止反射和序列化破坏。文章总结了对不同场景的选择建议,并提醒谨慎使用单例模式,以防代码耦合度高和难以测试。

笔者在项目开发过程中一直用的是本文介绍的方法双重检查锁定。这种方法属于延迟加载,能避免提前创建实例导致的资源浪费。

单例模式的核心要点有3方面:
1)唯一性:保证一个类在系统中只有一个实例。
2)控制访问:提供一个全局访问点来获取该实例。
3)延迟初始化(可选):实例化延迟到第一次使用时。

使用建议:
对于需要延迟加载且高并发的场景,建议优先选择静态内部类或双重检查锁定。在需要防反射或序列化攻击的场景,则必须使用枚举。



又到了金三银四求职季,我整理了一些互联网大厂的面试题,有需要的可关注工 众号:ItBeeCoder,发送“后端”获取
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/20190.html

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

相关文章

【Python项目】文本相似度计算系统

【Python项目】文本相似度计算系统 技术简介:采用Python技术、Django技术、MYSQL数据库等实现。 系统简介:本系统基于Django进行开发,包含前端和后端两个部分。前端基于Bootstrap框架进行开发,主要包括系统首页,文本分…

通过VSCode直接连接使用 GPT的编程助手

GPT的编程助手在VSC上可以直接使用 选择相应的版本都可以正常使用。每个月可以使用40条,超过限制要付费。 如下图对应的4o和claude3.5等模型都可以使用。VSC直接连接即可。 配置步骤如下: 安装VSCODE 直接,官网下载就行 https://code.vis…

神经网络剪枝技术的重大突破:sGLP-IB与sTLP-IB

神经网络剪枝技术的重大突破:sGLP-IB与sTLP-IB 在人工智能飞速发展的今天,深度学习技术已经成为推动计算机视觉、自然语言处理等领域的核心力量。然而,随着模型规模的不断膨胀,如何在有限的计算资源和存储条件下高效部署这些复杂的神经网络模型,成为了研究者们亟待解决的…

深度集成DeepSeek大模型:WebSocket流式聊天实现

目录 5分钟快速接入DeepSeek大模型:WebSocket实时聊天指南创建应用开发后端代码 (Python/Node.js)结语 5分钟快速接入DeepSeek大模型:WebSocket实时聊天指南 创建应用 访问DeepSeek官网 前往 DeepSeek官网。如果还没有账号,需要先注册一个。…

Javascript网页设计案例:通过PDF.js实现一款PDF阅读器,包括预览、页面旋转、页面切换、放大缩小、黑夜模式等功能

前言 目前功能包括: 切换到首页。切换到尾页。上一页。下一页。添加标签。标签管理页面旋转页面随意拖动双击后还原位置 其实按照自己的预期来说,有很多功能还没有开发完,配色也没有全都搞完,先发出来吧,后期有需要…

使用html css js 来实现一个服装行业的企业站源码-静态网站模板

最近在练习 前端基础,html css 和js 为了加强 代码的 熟悉程序,就使用 前端 写了一个个服装行业的企业站。把使用的技术 和 页面效果分享给大家。 应用场景 该制衣服装工厂官网前端静态网站模板主要用于前端练习和编程练习,适合初学者进行 HT…

Ubuntu24安装MongoDB(解压版)

目录 0.需求说明1.环境检查2.下载软件2.1.下载MongoDB服务端2.2.下载MongoDB连接工具(可略过)2.3.检查上传或下载的安装包 3.安装MongoDB3.1.编辑系统服务3.2.启动服务3.3.客户端连接验证3.3.1.创建管理员用户 4.远程访问4.1.开启远程访问4.2.开放防火墙 0.需求说明 问&#x…

打造一个有点好看的 uniapp 网络测速软件

大家好,我是一名前端小白。今天想和分享一个有点好看的网络测速 uniapp 组件的实现过程。这个组件不仅外观精美,而且具有完整的功能性,是一个非常适合学习和实践的案例。 设计理念 在开始coding之前,先聊聊设计理念。一个好的测…

ESP32 ESP-IDF TFT-LCD(ST7735 128x160)自定义组件驱动显示

ESP32 ESP-IDF TFT-LCD(ST7735 128x160)自定义组件驱动显示 🌿驱动参考来源:https://blog.csdn.net/weixin_59250390/article/details/142691848📍个人相关驱动内容文章:《ESP32 ESP-IDF TFT-LCD(ST7735 128x160) LVGL基本配置和使…

Redis的简单使用

1.Redis的安装Ubuntu安装Redis-CSDN博客 2.Redis在Spring Boot 3 下的使用 2.1 pom.xml <!-- Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifac…

elabradio入门第四讲——位同步(符号同步)

位同步是数字通信系统中特有的一种同步技术&#xff0c;又称为码元同步。在数字通信系统中&#xff0c;任何消息都是一串信号码元序列&#xff0c;接收端为了恢复码元序列&#xff0c;则需要知道每个码元的起止时刻&#xff0c;以便对于解调后的信号进行抽样判决&#xff0c;这…

网络安全推荐的视频教程 网络安全系列

第一章 网络安全概述 1.2.1 网络安全概念P4 网络安全是指网络系统的硬件、软件及其系统中的数据受到保护&#xff0c;不因偶然的或恶意的原因而遭到破坏、更改、泄露&#xff0c;系统连续可靠正常地运行&#xff0c;网络服务不中断。 1.2.3 网络安全的种类P5 &#xff08;1…

工控网络安全介绍 工控网络安全知识题目

31.PDR模型与访问控制的主要区别(A) A、PDR把对象看作一个整体 B、PDR作为系统保护的第一道防线 C、PDR采用定性评估与定量评估相结合 D、PDR的关键因素是人 32.信息安全中PDR模型的关键因素是(A) A、人 B、技术 C、模型 D、客体 33.计算机网络最早出现在哪个年代(B) A、20世…

Golang学习笔记_33——桥接模式

Golang学习笔记_30——建造者模式 Golang学习笔记_31——原型模式 Golang学习笔记_32——适配器模式 文章目录 桥接模式详解一、桥接模式核心概念1. 定义2. 解决的问题3. 核心角色4. 类图 二、桥接模式的特点三、适用场景1. 多维度变化2. 跨平台开发3. 动态切换实现 四、与其他…

DeepSeek预测25考研分数线

25考研分数马上要出了。 目前&#xff0c;多所大学已经陆续给出了分数查分时间&#xff0c;综合往年情况来看&#xff0c;每年的查分时间一般集中在2月底。 等待出成绩的日子&#xff0c;学子们的心情是万分焦急&#xff0c;小编用最近爆火的“活人感”十足的DeepSeek帮大家预…

AI性能极致体验:通过阿里云平台高效调用满血版DeepSeek-R1模型

前言 解决方案链接&#xff1a; https://www.aliyun.com/solution/tech-solution/deepseek-r1-for-platforms?utm_contentg_1000401616 DeepSeek是近期爆火的开源大语言模型&#xff08;LLM&#xff09;&#xff0c;凭借其强大的模型训练和推理能力&#xff0c;受到越来越多…

基于暗通道先验的图像去雾算法解析与实现

一、算法背景 何凯明团队于2009年提出的暗通道先验去雾算法《single image haze removal using dark channel prior》&#xff0c;通过统计发现&#xff1a;在无雾图像的局部区域中&#xff0c;至少存在一个颜色通道的像素值趋近于零。这一发现为图像去雾提供了重要的理论依据…

Visual Studio Code的下载安装与汉化

1.下载安装 Visual Studio Code的下载安装十分简单&#xff0c;在本电脑的应用商店直接下载安装----注意这是社区版-----一般社区版就足够用了---另外注意更改安装地址 2.下载插件 重启后就是中文版本了

遵循规则:利用大语言模型进行视频异常检测的推理

文章目录 速览摘要01 引言02 相关工作视频异常检测大语言模型 03 归纳3.1 视觉感知3.2 规则生成Normal and Anomaly &#xff08;正常与异常&#xff09;Abstract and Concrete &#xff08;抽象与具体&#xff09;Human and Environment &#xff08;人类与环境&#xff09; 3…

情书网源码 情书大全帝国cms7.5模板

源码介绍 帝国cms7.5仿《情书网》模板源码&#xff0c;同步生成带手机站带采集。适合改改做文学类的网站。 效果预览 源码获取 情书网源码 情书大全帝国cms7.5模板