作为一名Java开发工程师,你一定对**单例模式(Singleton Pattern)**不陌生。它是23种经典设计模式中最简单也是最常用的一种,用于确保一个类在整个应用程序中只有一个实例存在。

单例广泛应用于系统配置、数据库连接池、日志管理器、缓存服务等场景。本文将带你全面掌握 Java中实现单例的多种方式、线程安全性、懒加载机制、反射攻击防范、序列化处理以及在Spring中的应用


🧱 一、什么是单例模式?

单例模式(Singleton Pattern) 是一种创建型设计模式,其核心思想是:

✅ 确保一个类在整个程序运行期间只被初始化一次,并提供一个全局访问点。

单例的核心特点:

特性描述
私有构造方法防止外部通过 new 创建实例
静态私有实例指向自己唯一的实例对象
公共静态获取方法提供对外访问该实例的方法

📦 二、单例的基本实现方式

1. 饿汉式(Eager Initialization)

public class Singleton {// 类加载时就初始化private static final Singleton INSTANCE = new Singleton();// 构造方法私有private Singleton() {}// 提供唯一访问方法public static Singleton getInstance() {return INSTANCE;}
}

✅ 线程安全
⚠️ 类加载即初始化,浪费资源(非懒加载)


2. 懒汉式(Lazy Initialization)

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

⚠️ 非线程安全,在多线程下可能创建多个实例


3. 懒汉式 + 同步方法(线程安全)

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

✅ 线程安全
⚠️ 性能差,每次调用都要加锁


4. 双重检查锁定(Double-Checked Lockin

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 防止指令重排序


5. 静态内部类(IoDH,Initialization on Demand Holder)

public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}

✅ 线程安全
✅ 懒加载
✅ 推荐写法之一


6. 枚举(Enum)实现单例(《Effective Java》推荐)

public enum Singleton {INSTANCE;public void doSomething() {System.out.println("执行单例操作");}
}

调用方式:

Singleton.INSTANCE.doSomething();

✅ 线程安全
✅ 天然支持序列化/反序列化
✅ 防止反射攻击
✅ 推荐写法之一


🔐 三、单例的安全性问题

1. 如何防止反射破坏单例?

默认情况下,通过反射可以调用私有构造函数,从而创建多个实例。

解决办法:添加构造函数检测

private Singleton() {if (INSTANCE != null) {throw new RuntimeException("单例已被初始化");}
}

2. 如何防止序列化/反序列化破坏单例?

如果实现了 Serializable 接口,反序列化会生成新对象。

解决办法:添加 readResolve() 方法

protected Object readResolve() {return INSTANCE;
}

🔄 四、单例模式的应用场景

场景示例
日志记录器记录整个系统的日志
数据库连接池统一管理数据库连接
缓存服务如本地缓存、Redis客户端
配置管理器加载并读取配置文件
Spring Bean默认就是单例作用域
线程池统一管理线程资源
ID生成器保证ID全局唯一

🧩 五、单例模式的优缺点

优点缺点
节省内存资源生命周期长,可能造成内存泄漏
提供全局访问点违背单一职责原则(若逻辑复杂)
易于维护和控制不利于测试(依赖隐藏)
线程安全(部分实现)扩展困难(不符合开闭原则)

📦 六、Spring 中的单例 Bean

在Spring框架中,默认所有Bean都是单例的(@Scope("singleton")),但它的“单例”含义略有不同:

✅ 在Spring容器中,每个Bean定义只会有一个实例
❗ 与传统单例不同的是,它不是JVM级别的单例,而是Spring上下文内的单例

示例

@Component
public class MyService {public void sayHello() {System.out.println("Hello from singleton bean");}
}

注入使用:

@RestController
public class MyController {@Autowiredprivate MyService myService;@GetMapping("/hello")public String hello() {myService.sayHello();return "OK";}
}

🚫 七、常见误区与注意事项

错误正确做法
使用懒汉式未同步导致并发问题使用双重检查或静态内部类
忘记 volatile 导致指令重排添加 volatile 关键字
忽略反射攻击添加构造函数检查
忽略序列化破坏添加 readResolve() 方法
将单例用于可变状态应保持不可变性或加锁处理
单例中包含大量业务逻辑应拆分职责,避免违反单一职责原则

📊 八、六种常见单例实现对比表

实现方式是否线程安全是否懒加载是否推荐
饿汉式
懒汉式
同步方法懒汉式
双重检查锁定
静态内部类
枚举✅✅✅(最佳实践)

📎 九、附录:单例相关工具与框架速查表

工具/框架用途
Lombok 的 @UtilityClass帮助构建无实例的工具类
Spring 的 @Component / @Service自动注册为单例Bean
Guice / DaggerDI框架中的单例支持
MapStruct / Dozer单例工具类转换数据
Jackson / Gson单例对象的序列化控制
Mockito单例测试时需使用 Spy 或注入方式
ThreadLocal若误用可能导致伪单例问题
Flyweight 模式与单例类似,但允许多个共享实例

✅ 十、总结:Java 单例类关键知识点一览表

内容说明
定义整个程序中仅允许存在一个实例
核心结构私有构造器 + 私有静态实例 + 公共静态访问方法
实现方式饿汉式、懒汉式、双重检查、静态内部类、枚举
线程安全枚举、双重检查、静态内部类是线程安全的
懒加载懒汉式、双重检查、静态内部类支持懒加载
Spring 中的单例容器内单例,非JVM级别
注意事项防止反射、序列化破坏,合理使用
推荐写法枚举 > 静态内部类 > 双重检查

如果你正在准备一篇面向初学者的技术博客,或者希望系统回顾Java基础知识,这篇文章将为你提供完整的知识体系和实用的编程技巧。

欢迎点赞、收藏、转发,也欢迎留言交流你在实际项目中遇到的单例类相关问题。我们下期再见 👋

📌 关注我,获取更多Java核心技术深度解析!

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

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

相关文章

面向对象设计

你列出的这些属于 C 高级开发中面向对象设计与架构设计的核心知识,也是面试高级工程师岗位必问的内容。下面我按顺序,深入讲解每一项概念、原理、用途,并穿插 C 示例。✅ 1. 设计原则(SOLID)SOLID 是面向对象设计的五大…

IntelliJ IDEA让我的开发效率翻倍:从新手到高效开发者的进阶之路

IntelliJ IDEA让我的开发效率翻倍:从新手到高效开发者的进阶之路 🌟 嗨,我是IRpickstars! 🌌 总有一行代码,能点亮万千星辰。 🔍 在技术的宇宙中,我愿做永不停歇的探索者。 ✨ 用…

css sprites使用

CSS Sprites 是一种将多个小图标或背景图像合并到一个大图中的技术。通过减少HTTP请求次数,可以显著提高页面加载速度。其核心原理是:通过设置元素的背景图(background-image)为这个大图,然后调整背景位置(…

分布式爬虫在电商平台商品数据大规模采集中的技术应用

在电商平台商品数据大规模采集场景中,分布式爬虫凭借其高效、可扩展、抗风险的特性,成为突破单节点爬虫性能瓶颈的核心技术方案。以下从技术架构、关键技术点、电商场景适配及挑战应对四个维度,解析其具体应用:一、分布式爬虫的核…

Linux的`if test`和`if [ ]中括号`的取反语法比较 笔记250709

Linux的if test和if 中括号的取反语法比较 笔记250709 Linux的 test命令(或等价中括号写法 [空格expression空格])的用法详解. 笔记250709 四种取反语法: if ! test -e xxx ;then... 和 if test ! -e xxx ;then... 和 if ! [ -e xxx ] ;then... 和 if …

记录使用ubuntu16.04编译aosp(android8.1与10)遇到的问题

一、前言: 本来打算用wsl来编译AOSP,但是折腾了好几天,以失败告终。后来使用vmware反而成功了。 本篇同样会把wsl遇到的问题与尝试记录下来。 环境:vmware ubuntu16.04。 为什么会使用ubuntu16.04呢,因为在公司有一…

hiredis window之RFDMap

简介 RFDMap用于将socket分配映射成连续的文件描述符,同时管理回收的文件描述符,因为ae构架中管理fd与对应事件处理器使用的是数据,fd作为数组下标 结构 #mermaid-svg-zQz2LTrKRi0LQTII {font-family:"trebuchet ms",verdana,arial…

RustFS一款Rust 驱动的 高性能 分布式存储系统

演示地址:https://play.rustfs.com/browser 访问账号(默认 rustfsadmin)。 访问密钥(默认 rustfsadmin)。 下载mc https://dl.min.io/client/mc/release可以直接在 Linux 系统上安装 mc(,然后访…

微软 Bluetooth LE Explorer 实用工具的详细使用分析

微软 Bluetooth LE Explorer 实用工具的详细使用分析 文章目录 微软 **Bluetooth LE Explorer** 实用工具的详细使用分析1. **工具定位与核心功能**2. **关键特性与更新**3. **使用场景示例**4. **系统要求与依赖**5. **与专业工具对比**6. **局限性**7. **实践建议**结论以下是…

centos 7.6安装mysql8

在 CentOS 7.6 上安装 MySQL 8.0.42 的步骤如下,基于搜索结果中的最新信息: 下载 MySQL 8.0.42 安装包 https://dev.mysql.com/downloads/mysql/从 MySQL 官方网站下载 mysql-8.0.42-1.el7.x86_64.rpm-bundle.tar 文件: 官方下载地址&#xf…

CentOS7更换阿里云yum源

问题:刚刚在本地安装了CentOS7虚拟机,使用yum安装vim软件时(最小化安装只有vi没有vim)出现下面的报错原因 :CentOS7 已于2024-6-30停止维护,官方镜像源已不可用,可以更换为阿里云镜像源解决&…

UE5内置插件 AnimToTexture 简单入门

开启插件 首先安装插件,然后重启。打开显示插件内容我们就可以找到插件自带的转换内容将骨骼网格体转换为顶点动画有两种方式: 最简单的记录每个顶点的位置然后通过切换拾取颜色偏移实现记录骨骼的变换,然后通过贴图去修改骨骼位置计算 这两种…

如何搭建Appium环境?

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快1、安装Java Development Kit(JDK)前往Oracle官网下载JDK。在https://www.oracle.com/java/technologies/javase-jdk11-downloads.html 找到…

Android kotlin 协程的详细使用指南

Android Kotlin 协程的详细使用指南,结合核心概念、实战场景和最佳实践:一、协程基础概念‌协程本质‌协程是轻量级线程,通过挂起/恢复机制实现并发,相比线程节省90%以上的内存开销。其核心优势在于结构化并发和挂起函数的协作式调…

什么是 AMR 格式?简鹿音频转换器轻松批量转换 AMR 为 MP3

AMR 格式是一种比较特殊但又常见的音频格式,而MP3 格式则是大家耳熟能详的通用音频格式。那么,它们之间有什么区别?又该如何把 AMR 文件转换成更常用的 MP3 呢?下面我们就来通俗地了解一下。一、什么是 AMR 格式?AMR&a…

C++11 std::move与std::move_backward深度解析

文章目录移动语义的革命性意义std::move:正向范围移动函数原型与核心功能关键特性与实现原理适用场景与代码示例危险区域:重叠范围的未定义行为std::move_backward:反向安全移动函数原型与核心功能关键特性与实现原理适用场景与代码示例重叠范…

订单初版—2.生单链路中的技术问题说明文档

大纲1.生单链路的业务代码2.生单链路中可能会出现数据不一致的问题3.Seata AT模式下的分布式事务的原理4.Seata AT模式下的分布式事务的读写隔离原理5.Seata AT模式下的死锁问题以及超时机制6.Seata AT模式下的读写隔离机制的影响7.生单链路使用Seata AT模式的具体步骤8.生单链…

跨平台ROS2视觉数据流:服务器运行IsaacSim+Foxglove本地可视化全攻略

任务目标 本教程将完整实现: 在服务器无头模式下运行IsaacSim,并在本地显示GUI界面 通过IsaacSim的ROS2 Bridge发布图像数据 在本地Foxglove中实时可视化服务器端的ROS2数据流 实现步骤 1. 服务器无头运行IsaacSim 本地GUI显示 在服务器端执行&am…

【机器学习笔记Ⅰ】 8 多元梯度下降法

多元线性回归的梯度下降法详解 多元线性回归(Multiple Linear Regression)是多个自变量(特征)与一个因变量(目标)之间的线性关系建模,梯度下降法用于优化模型参数(权重和偏置&#x…

C++——从结构体到类与对象

C 类与对象详解:从结构体到面向对象编程C 的面向对象编程(OOP)核心是 类(Class) 和 对象(Object)。类是用户自定义的数据类型,用于封装数据(属性)和操作数据的…