讲师中心 微信公众号
AI工具推荐 视频效率加速

Java单例模式与多例模式应用与实现

浅涛大大_1596

浅涛大大_1596

发布时间:2026-01-11 12:15:08

|

692人浏览过

|

来源于php中文网

原创

推荐用双重检查锁(DCL)+ volatile 实现线程安全单例:外层判空减少锁竞争,内层加锁保证唯一性,volatile 防止指令重排序;枚举单例可防反射和序列化攻击但不支持延迟加载与继承。

java单例模式与多例模式应用与实现

单例模式怎么写才真正线程安全

Java里最常写的 Singleton,往往在高并发下出问题。不是加了 synchronized 就万事大吉,也不是靠 static 字段就能一劳永逸。

推荐用双重检查锁(DCL)+ volatile,这是 JDK 6+ 下兼顾性能与安全的写法:

public class Singleton {
    private static volatile Singleton instance;
<pre class='brush:java;toolbar:false;'>private Singleton() {}

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

}

  • volatile 防止指令重排序,避免其他线程拿到未初始化完成的对象
  • 两次 if (instance == null) 判断:外层减少锁竞争,内层保证唯一性
  • 禁止反射攻击?可在构造函数里加 if (instance != null) throw new RuntimeException("Singleton already initialized")
  • 序列化破坏单例?需实现 readResolve() 方法返回 instance

Spring 默认是单例,但为什么有时候像“多例”

Spring 的 @Scope("singleton") 是容器级单例——整个 ApplicationContext 中只存在一个 bean 实例,但这个“单例”不等于线程安全,也不等于全局唯一对象引用。

立即学习“Java免费学习笔记(深入)”;

  • 如果 bean 有可变状态(比如含 private List<string> cache</string>),多个线程同时操作它,照样出错
  • Web 环境中,request 或 session 作用域的 bean 看起来“每次请求都新建”,其实是 Spring 在每次请求开始时从代理获取新实例,底层仍是工厂管理
  • 想让某个 bean 每次 getBean() 都返回新实例?显式声明 @Scope("prototype"),但注意:prototype bean 的依赖注入仍由容器完成,只是它本身不被缓存

什么时候必须用多例(prototype),而不是硬写 new

手动 new XxxService() 看似简单,但会绕过 Spring 容器的生命周期管理、AOP 代理、依赖注入和事务控制——这在真实项目里几乎不可接受。

  • 需要带不同初始化参数的多个实例?用 ObjectFactory<xxxservice></xxxservice> 或 Provider<xxxservice></xxxservice> 延迟获取,Spring 4.3+ 支持自动注入
  • 高频创建/销毁的轻量对象(如 DTO、Builder)?直接 new 更合理,不属于 Spring 管理范畴
  • 测试中模拟不同行为?用 @MockBean 或 @SpyBean 替换 prototype bean,比改代码更可控
  • 注意:prototype bean 内部若持有 singleton bean 引用,那个 singleton 仍是共享的——多例 ≠ 全隔离

枚举实现单例真的万无一失?

Joshua Bloch 在《Effective Java》里力推枚举单例,确实能天然防止反射和序列化攻击,写法极简:

public enum Singleton {
    INSTANCE;
<pre class='brush:java;toolbar:false;'>public void doSomething() { /* ... */ }

}

但它也有现实约束:

  • 无法继承(枚举类隐式 final),不能实现需要扩展的抽象基类
  • 不能延迟加载:JVM 加载类时就初始化所有枚举实例,哪怕你永远没调用 INSTANCE
  • 某些框架(如部分 RPC 序列化工具)对枚举支持不一致,可能报 IllegalArgumentException: No enum constant
  • 单元测试中难以 mock 枚举方法,得靠 PowerMock 或改用接口+委托

真要选枚举单例,确保它只做纯粹的状态无关工具类,不涉及外部资源或复杂初始化逻辑。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

小橡皮AI

一款AI工具,主要用于小橡皮一键去AI味,将机器味重的内容改得更有活人感,防止因为 AI 内容被平台打上 AI 标签,以及限流,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

2871

2025.08.06

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

517

2026.01.26

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

7199

2023.08.02

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

549

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1698

2024.03.01

session失效的原因
session失效的原因

session失效的原因有会话超时、会话数量限制、会话完整性检查、服务器重启、浏览器或设备问题等等。详细介绍:1、会话超时:服务器为Session设置了一个默认的超时时间,当用户在一段时间内没有与服务器交互时,Session将自动失效;2、会话数量限制:服务器为每个用户的Session数量设置了一个限制,当用户创建的Session数量超过这个限制时,最新的会覆盖最早的等等。

580

2023.10.17

session失效解决方法
session失效解决方法

session失效通常是由于 session 的生存时间过期或者服务器关闭导致的。其解决办法:1、延长session的生存时间;2、使用持久化存储;3、使用cookie;4、异步更新session;5、使用会话管理中间件。

876

2023.10.18

cookie与session的区别
cookie与session的区别

本专题整合了cookie与session的区别和使用方法等相关内容,阅读专题下面的文章了解更详细的内容。

1966

2025.08.19

DBeaver怎么导入数据
DBeaver怎么导入数据

DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。

20

2026.11.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn