0

0

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

P粉602998670

P粉602998670

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

|

672人浏览过

|

来源于php中文网

原创

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

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

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

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

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

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

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

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

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

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

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

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

css3实现多款创意按钮
css3实现多款创意按钮

css3实现多款创意按钮,按钮需要用的地方太多了,例如商城网站,前台的会员登录与注册需要用到按钮,后台增删改查我们有时候也会需要用到按钮,多款创意按钮,不同样式。php中文网推荐下载!

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

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

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

public enum Singleton {
    INSTANCE;
public void doSomething() { /* ... */ }

}

但它也有现实约束:

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

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

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

831

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

737

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

733

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

396

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16925

2023.08.03

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

80

2026.01.09

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.4万人学习

C# 教程
C# 教程

共94课时 | 6.5万人学习

Java 教程
Java 教程

共578课时 | 44.8万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号