news 2026/9/24 3:03:55

设计模式之【单例模式】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
设计模式之【单例模式】

单例模式(Singleton Pattern)

单例模式是设计模式中创建型模式的经典代表,核心思想是:保证一个类在整个应用程序中只有一个实例,并提供一个全局访问点来获取这个实例。
简单来说,单例模式就是让某个类 “独一无二”—— 无论调用多少次创建方法,返回的都是同一个对象,避免重复创建对象消耗资源(比如数据库连接池、配置类、日志工具类等场景)。

单例模式的实际应用场景
工具类:比如 java.lang.Runtime(JDK 内置饿汉单例)、日志工具类、日期工具类;
资源密集型对象:数据库连接池、Redis 连接池、线程池(避免重复创建消耗资源);
配置类:全局配置类(应用启动后加载一次配置,全局复用);
Spring 容器:Spring 中默认所有 Bean 都是单例(通过容器管理唯一实例);
缓存:应用级缓存(比如本地缓存工具,单例保证缓存数据全局一致)。

一、核心设计原则

私有构造方法:禁止外部通过 new 关键字创建实例;
私有静态实例:类内部维护唯一的实例对象;
公共静态方法:提供全局访问点,返回这个唯一实例。

二、Java 中常见的单例实现方式(从易到难,从有坑到最优)

单例模式的实现关键是线程安全和懒加载(按需创建实例),不同实现方式的核心差异也在这两点。

1. 饿汉式(饿汉单例)—— 最简单,线程安全但无懒加载

核心逻辑:类加载时就创建实例(“饿” 意味着迫不及待创建),JVM 类加载机制保证线程安全。

public class HungrySingleton { // 1. 私有静态实例:类加载时直接创建(唯一实例) private static final HungrySingleton INSTANCE = new HungrySingleton(); // 2. 私有构造方法:禁止外部new private HungrySingleton() {} // 3. 公共静态方法:返回唯一实例 public static HungrySingleton getInstance() { return INSTANCE; } // 测试方法 public void doSomething() { System.out.println("饿汉单例执行方法,实例地址:" + this); } }

特点:
✅ 线程安全(JVM 类加载时仅创建一次实例);
❌ 无懒加载(类加载时就创建,即使没用到也会占用内存);
❌ 无法控制实例创建时机(比如需要读取配置后再创建的场景不适用);
✅ 实现简单,无并发问题。

2. 懒汉式(懒汉单例)—— 懒加载但非线程安全(基础版)

核心逻辑:第一次调用 getInstance() 时才创建实例(“懒” 意味着按需创建),但多线程下会创建多个实例。

public class LazySingleton { // 1. 私有静态实例:初始为null(懒加载) private static LazySingleton INSTANCE = null; // 2. 私有构造方法 private LazySingleton() {} // 3. 公共静态方法:首次调用时创建实例 public static LazySingleton getInstance() { if (INSTANCE == null) { // 判空:未创建则new INSTANCE = new LazySingleton(); } return INSTANCE; } public void doSomething() { System.out.println("懒汉单例执行方法,实例地址:" + this); } }

问题:
多线程场景下,多个线程同时进入 if (INSTANCE == null),会创建多个实例(破坏单例特性)。比如:

// 多线程测试 public class SingletonTest { public static void main(String[] args) { for (int i = 0; i < 5; i++) { new Thread(() -> { LazySingleton instance = LazySingleton.getInstance(); instance.doSomething(); }).start(); } } }

输出会看到多个不同的实例地址,说明单例被破坏。

3.懒汉式(加锁版)—— 线程安全但性能差

核心逻辑:给 getInstance() 加 synchronized 锁,保证同一时间只有一个线程执行创建逻辑。

public class LazySingletonWithLock { private static LazySingletonWithLock INSTANCE = null; private LazySingletonWithLock() {} // 加synchronized锁,保证线程安全 public static synchronized LazySingletonWithLock getInstance() { if (INSTANCE == null) { INSTANCE = new LazySingletonWithLock(); } return INSTANCE; } }

特点:
✅ 线程安全;
✅ 懒加载;
❌ 性能差(每次调用 getInstance() 都要加锁,即使实例已创建)。

4. 双重检查锁(DCL)—— 线程安全 + 懒加载 + 高性能(推荐)

核心逻辑:两次判空 + 加锁,既保证线程安全,又避免频繁加锁(最优的懒加载单例)。

public class DclSingleton { // 关键:volatile 关键字,禁止指令重排(必须加!) private static volatile DclSingleton INSTANCE = null; private DclSingleton() {} public static DclSingleton getInstance() { // 第一次判空:实例已创建时,直接返回,无需加锁(提升性能) if (INSTANCE == null) { synchronized (DclSingleton.class) { // 类锁,只锁创建逻辑 // 第二次判空:防止多个线程等待锁后重复创建 if (INSTANCE == null) { INSTANCE = new DclSingleton(); } } } return INSTANCE; } }

关键细节:
volatile 必须加:INSTANCE = new DclSingleton() 不是原子操作,分为 3 步:
分配内存;2. 初始化对象;3. 把 INSTANCE 指向内存地址。
不加 volatile 可能发生指令重排(步骤 2 和 3 交换),导致其他线程拿到 “未初始化完成的实例”。
双重判空:第一次判空避免频繁加锁,第二次判空避免多线程重复创建。
特点:
✅ 线程安全;
✅ 懒加载;
✅ 高性能(仅首次创建时加锁);
✅ 实际开发中最常用(比如 Spring 中很多单例 Bean 底层用此方式)。

5. 静态内部类(Holder 模式)—— 线程安全 + 懒加载(优雅版)

核心逻辑:利用 JVM 静态内部类的加载机制,实现懒加载 + 线程安全(无需加锁)。

public class HolderSingleton { // 私有构造方法 private HolderSingleton() {} // 静态内部类:只有调用 getInstance() 时才加载 private static class SingletonHolder { // 内部类加载时创建实例,JVM 保证线程安全 private static final HolderSingleton INSTANCE = new HolderSingleton(); } // 公共方法:返回内部类中的实例 public static HolderSingleton getInstance() { return SingletonHolder.INSTANCE; } }

特点:
✅ 线程安全(JVM 加载内部类时仅创建一次实例);
✅ 懒加载(内部类只有被调用时才加载);
✅ 无锁,性能高;
✅ 代码优雅,推荐使用(比 DCL 更简洁)。

6. 枚举单例 —— 绝对线程安全 + 防反射破坏(终极版)

核心逻辑:利用 Java 枚举的特性,天然保证单例(无法通过反射 / 序列化破坏)。

public enum EnumSingleton { // 唯一实例(枚举常量) INSTANCE; // 业务方法 public void doSomething() { System.out.println("枚举单例执行方法,实例地址:" + this); } } // 直接通过枚举常量获取实例 EnumSingleton instance = EnumSingleton.INSTANCE; instance.doSomething();

特点:
✅ 绝对线程安全(JVM 保证枚举常量唯一);
✅ 防止反射破坏(反射无法创建枚举实例);
✅ 防止序列化破坏(枚举序列化机制特殊,反序列化仍返回同一实例);
❌ 无懒加载(枚举类加载时创建实例);
✅ 《Effective Java》推荐的最优单例方式(无任何坑)。

特点总结

单例模式的核心是保证类只有一个实例 + 全局访问点,核心价值是节省资源、保证状态一致;
实际开发中优先选 双重检查锁(DCL) 或 静态内部类(懒加载 + 高性能),追求绝对安全选 枚举单例;
避免使用基础版懒汉式(线程不安全)和加锁懒汉式(性能差);
单例模式的坑主要在线程安全和指令重排,DCL 中 volatile 必须加,枚举单例可规避所有坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 3:12:42

卷王问卷考试系统 JMeter 压测报告分析

一、测试整体概况 本次对系统核心接口进行梯度压测&#xff0c;测试时长约3分钟&#xff0c;总请求数1531次&#xff0c;全链路错误率0.00%&#xff0c;无请求失败、超时或服务崩溃&#xff0c;系统在压测压力下基础稳定性达标&#xff0c;未出现严重可用性问题。二、核心指标深…

作者头像 李华
网站建设 2026/9/23 21:43:24

终极Steam创意工坊下载指南:WorkshopDL免费跨平台解决方案

终极Steam创意工坊下载指南&#xff1a;WorkshopDL免费跨平台解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否拥有GOG或Epic平台的游戏&#xff0c;却眼馋Steam创…

作者头像 李华
网站建设 2026/9/19 7:39:33

WarcraftHelper终极指南:让魔兽争霸3在现代系统重获新生

WarcraftHelper终极指南&#xff1a;让魔兽争霸3在现代系统重获新生 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 魔兽争霸3作为经典的即时战略游戏…

作者头像 李华
网站建设 2026/9/17 7:43:17

无锁队列简介

无锁 多线程编程中&#xff0c;有lock-free(无锁)&#xff0c;wait-free(无等待)&#xff0c;blocking(阻塞)&#xff0c;Non-blocking(非阻塞)。 阻塞blocking 在阻塞算法中&#xff0c;线程尝试获取一个不可用的资源时会被挂起&#xff08;即进入阻塞状态&#xff09;&#x…

作者头像 李华
网站建设 2026/9/18 22:13:42

Napkin AI:用文字一键生成专业图表的神器

前言 在日常工作中&#xff0c;你是否也曾为将文字内容转化为流程图、信息图而头疼&#xff1f;明明思路清晰&#xff0c;却要在PPT或Canva里花几十分钟拖拽图形、调整线条、对齐位置。Napkin AI的出现&#xff0c;彻底改变了这一局面——它把复杂的设计过程&#xff0c;简化成…

作者头像 李华
网站建设 2026/9/19 20:16:49

如何快速实现WPS与Zotero无缝集成:终极学术写作效率指南

如何快速实现WPS与Zotero无缝集成&#xff1a;终极学术写作效率指南 【免费下载链接】WPS-Zotero An add-on for WPS Writer to integrate with Zotero. 项目地址: https://gitcode.com/gh_mirrors/wp/WPS-Zotero WPS-Zotero插件是专为学术工作者设计的革命性工具&#…

作者头像 李华