0

0

Java单例模式与多例模式的实现原理

P粉602998670

P粉602998670

发布时间:2026-01-13 12:26:02

|

861人浏览过

|

来源于php中文网

原创

单例模式只能有一个实例的关键在于私有化构造方法并由类内部管理唯一实例的创建与返回;常用实现有饿汉式(类加载时初始化,线程安全但可能浪费资源)和懒汉式(延迟初始化,需synchronized或dcl+volatile防重排);静态内部类方式因jvm类加载机制天然线程安全且延迟加载,更推荐;多例模式通过key映射有限实例池,用concurrenthashmap保证线程安全;spring的@scope("singleton")是容器级单例,与编码级单例模式无必然关联,二者控制权不同。

java单例模式与多例模式的实现原理

单例模式为什么只能有一个实例

关键在于控制类的构造方法访问权限,并在类内部管理唯一实例的创建与返回。Java 中最常用的是「懒汉式(线程安全版)」和「饿汉式」,区别在于实例化时机和并发处理方式。

  • private static 字段保存唯一实例,外部无法直接 new
  • 构造方法必须是 private,否则任何代码都能绕过单例逻辑
  • 饿汉式在类加载时就初始化 instance = new Singleton(),天然线程安全但可能浪费资源
  • 懒汉式用 synchronized 修饰 getInstance() 方法或采用双重检查锁(DCL),延迟初始化但需注意 volatile 修饰 instance 防止指令重排
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;
    }
}

多例模式不是“多个单例”,而是有限实例池

多例(Multiton)本质是把“唯一实例”扩展为“固定数量的实例”,通常按键(key)索引,比如按配置名、线程ID 或环境类型返回不同实例。它不保证全局唯一,但保证每个 key 对应的实例只创建一次。

  • 核心结构是 private static Map<string multiton> instances = new HashMap()</string>
  • 构造方法仍为 private,避免外部随意创建
  • 通过 get(String key) 获取实例,首次调用才创建,后续复用
  • 注意:若 key 不可控(如用户输入),需加白名单或哈希截断,防止内存泄漏
  • 和单例一样,多例也需考虑线程安全——ConcurrentHashMapHashMap + synchronized 更轻量
public class Multiton {
    private static final Map<String, Multiton> instances = new ConcurrentHashMap<>();
    private final String name;
    private Multiton(String name) { this.name = name; }
    public static Multiton get(String key) {
        return instances.computeIfAbsent(key, Multiton::new);
    }
}

Spring 中的 @Scope 注解不是实现模式,而是容器行为契约

很多人混淆「单例模式」和 Spring 的 @Scope("singleton")。前者是编码层面的类设计约束,后者是 Spring IoC 容器对 Bean 生命周期的管理策略。同一个类,既可被写成单例模式,也可在 Spring 中声明为 @Scope("prototype") —— 此时容器每次 getBean() 都新建实例,完全绕过类内部的单例逻辑。

睿拓智能网站系统-网上商城
睿拓智能网站系统-网上商城

睿拓智能网站系统-网上商城1.0免费版软件大小:5M运行环境:asp+access本版本是永州睿拓信息专为电子商务入门级用户开发的网上电子商城系统,拥有产品发布,新闻发布,在线下单等全部功能,并且正式商用用户可在线提供多个模板更换,可实现一般网店交易所有功能,是中小企业和个人开展个人独立电子商务商城最佳的选择,以下为详细功能介绍:1.最新产品-提供最新产品发布管理修改,和最新产品订单查看2.推荐产

下载
  • @Scope("singleton")(默认):Spring 容器中该 Bean 的定义只有一个共享实例,但和 Java 单例模式无必然关系
  • @Scope("prototype"):每次请求都新建 Bean 实例,此时即使类内部用了 DCL 单例写法,只要不被 Spring 管理或被多次注册,就不生效
  • 真正冲突点在于:如果一个类自己实现了单例模式,又交给 Spring 管理为 prototype,会导致语义矛盾——开发者以为每次都是新对象,实则内部状态被多个 Bean 实例共享

为什么静态内部类方式比双重检查锁更推荐

因为它是 JVM 层面保障的线程安全 + 延迟加载,无需 synchronizedvolatile,代码更简洁,且能避免 DCL 在早期 JDK 版本中的潜在问题。

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

  • 静态内部类 Holder 只在首次调用 getInstance() 时才被加载,触发其 static 字段初始化
  • JVM 保证类加载过程的线程安全性,天然规避了同步开销
  • 相比饿汉式,不浪费资源;相比 DCL,没有指令重排风险,也不依赖 volatile 的语义理解深度
public class Singleton {
    private Singleton() {}
    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}
真正容易被忽略的是:单例/多例的边界只在「谁负责控制实例数量」。手写单例控制权在类自身;Spring 控制权在容器;而像数据库连接池、线程池这类“多实例复用”机制,控制权又在独立的工厂或管理者——它们都不是语言层面的模式,而是运行时策略。写代码时得先想清楚:这个“唯一性”到底该由谁来保证。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

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

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

156

2025.08.06

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

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

88

2026.01.26

string转int
string转int

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

1010

2023.08.02

c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

75

2025.10.23

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

764

2023.08.10

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

77

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

40

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

67

2025.11.17

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

4

2026.03.10

热门下载

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

精品课程

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

共23课时 | 4.3万人学习

C# 教程
C# 教程

共94课时 | 11.1万人学习

Java 教程
Java 教程

共578课时 | 80.4万人学习

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

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