news 2026/1/9 10:31:26

设计模式学习(4) 23-1 单例模式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
设计模式学习(4) 23-1 单例模式

0.个人感悟

  • 单例是老生常谈的模式。工作中也用的很多,比如各种全局管理类、工厂类。结合场景,选择合适的实现方式
  • 它核心思路是想办法让类只有一个实例,对外只提供一个获取实例的方法(封装),然后是安全和效率考虑
    • 自己实现
      • 提前将实例准备好-饿汉
        • 静态常量 静态代码块 效率低
      • 使用时再创建实例-懒汉
        • 初版实现 不安全
        • 进阶版-同步方法 效率低
        • 终级版-双重检查 兼顾安全和效率 推荐
    • JVM机制
      • 静态内部类 推荐
      • 枚举 推荐
  • 扩展知识点。在代码示例后面罗列了扩展知识点(比如类加载等)和了解这些知识点的书籍推荐,感兴趣可以引申学习下,我也留些坑,后续记录相关知识点时链接过去

1.概念

Intent: Ensure a class only has one instance, and provide a global point of access to it. – 《Design Patterns: Elements of Reusable Object-Oriented Software》

翻译:

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点

理解:
采取一定的方法使得某个类在整个系统中,有且仅有一个实例

2.适配场景

与定义适配,某个类没有状态的概念,仅需要有一个全局唯一的实例,比如各种工厂类、管理类等

3.实现方法

  • 实例静态化,与class绑定
  • 私有化构造方法
  • 对外提供唯一静态方法

3.1 饿汉式

3.1.1 实现

饿汉顾名思义,很饿,想提供者赶紧做好
写法1:静态常量写法

/** * @Description 单例示例 饿汉-静态常量 * @Author bigHao * @Date 2025/12/17 */publicclassSingleton{// 2.静态常量,类加载时便创建privatestaticfinalSingletoninstance=newSingleton();// 1.构造方法私有privateSingleton(){}// 3.只暴露一个公共静态方法,返回实例/** * @return Singleton 单例 * @description 获取单例 * @author bigHao * @date 2025/12/17 **/publicstaticSingletongetInstance(){returninstance;}}

写法2:静态代码块写法

/** * @Description 单例示例 饿汉-静态代码块 * @Author bigHao * @Date 2025/12/17 */publicclassSingleton{privatestaticfinalSingletoninstance;// 静态常量,静态块加载static{instance=newSingleton();}privateSingleton(){}/** * @return Singleton 单例 * @description 获取单例 * @author bigHao * @date 2025/12/17 **/publicstaticSingletongetInstance(){returninstance;}}

调用方式:都是通过Class.获取实例方法

publicclassTest{staticvoidmain(){// 调用方只能通过暴露的方法调用,无法new的方式创建实例Singletoninstance=Singleton.getInstance();}}

3.1.2 优缺点

  • 优点:
    • 写法简单,JVM加载类时创建对象,避免线程安全问题
  • 缺点:
    • 内存浪费。未实现懒加载(lazy loding)

3.1.3 涉及知识点

  1. 类的加载机制和生命周期
    推荐书籍:《深入理解Java虚拟机》

3.2 懒汉式-线程不安全

3.2.1 实现方法

需要的时候再创建实例

/** * 单例示例 懒汉-线程不安全 */publicclassSingleton{privatestaticSingletoninstance;privateSingleton(){}/** * @return Singleton 单例 * @description 获取单例-线程不安全 * @author bigHao * @date 2025/12/17 **/publicstaticSingletongetInstance(){// 非原子操作,多线程场景会有多个线程进入到if内,从而创建多个实例if(instance==null){instance=newSingleton();}returninstance;}}

多线程场景,可能会有多个线程同时执行if中的代码,创建多个实例
测试

/** * @Description 测试单例-懒汉-线程不安全 * @Author bigHao * @Date 2025/12/17 */publicclassTest{staticvoidmain(){// 测试线程不安全Set<String>instanceSet=newHashSet<>(100);// 多线程获取100次实例for(inti=0;i<100;i++){newThread(()->{instanceSet.add(Singleton.getInstance().toString());}).start();}// 因为set会去重,这里如果size不为1,意味着线程不安全,多个实例System.out.println(STR."instance size \{instanceSet.size()} 线程是否安全: \{1 == instanceSet.size()} ");// false}}

3.2.2 优缺点

  • 优点:
    • 实现了懒加载,节约空间
  • 缺点:
    • 线程不安全

3.2.3 涉及知识点

3.3 懒汉式-同步方法

3.3.1 实现方法

静态方法加锁

/** * @Description 单例示例 懒汉-同步方法 * @Author bigHao * @Date 2025/12/17 */publicclassSingleton{privatestaticSingletoninstance;privateSingleton(){}/** * @return Singleton 单例 * @description 获取单例-同步方法 * @author bigHao * @date 2025/12/17 **/publicstaticsynchronizedSingletongetInstance(){// 只实例化一次if(instance==null){instance=newSingleton();}returninstance;}}

3.3.2 优缺点

  • 优点:
    • 实现了懒加载
    • 线程安全
  • 缺点:
    • 效率低。所有线程都需要进行同步

3.4 懒汉式-双重检查

3.4.1 实现方法

  • 双重检查,第一次检查可以过滤掉一些线程,直接获取创建好的实例
    第二次检查,加锁,只有一个线程进行对象创建
  • 使用volatile关键字,禁止指令重排,保证创建操作的原子性
/** * @Description 单例示例 双重检查+禁止指令重排 * @Author bigHao * @Date 2025/12/17 */publicclassSingleton{// volatile 禁止JVM对这个对象涉及到的代码重排序privatestaticvolatileSingletoninstance;privateSingleton(){}/** * @return Singleton 单例 * @description 获取单例-双重检查 * @author bigHao * @date 2025/12/17 **/publicstaticSingletongetInstance(){// 第一次判断示例是否存在;多线程场景下会放过一些线程if(instance==null){// 再次判断,针对被放过的线程,这里加锁进行等待synchronized(Singleton.class){if(instance==null){instance=newSingleton();}}}returninstance;}}

3.4.2 优缺点

  • 优点:
    • 实现了懒加载
    • 线程安全
    • 双重检查,效率高

3.4.3 涉及知识点

  1. 指令重排
    JVM创建实例时一般分为以下几步:
    1. 开辟内存空间
    2. 初始化对象
    3. 实例的引用指向第1步中的空间地址
      JVM优化代码过程中,可能对步骤进行了优化,变成132,这样就有很多意想不到的问题。
      推荐书籍:《Java并发编程实战》

3.5 静态内部类

3.5.1 实现方法

利用静态内部类的机制,JVM帮助实现:

  • 静态内部类在需要的时候才被实例化
  • 加载的时候只有一个线程
/** * @Description 单例示例 静态内部类 * @Author bigHao * @Date 2025/12/17 */publicclassSingleton{privateSingleton(){}// 静态内部类privatestaticclassSingletonInstance{privatestaticfinalSingletonINSTANCE=newSingleton();}/** * @return Singleton 单例 * @description 获取单例-静态内部类 * @author bigHao * @date 2025/12/17 **/publicstaticSingletongetInstance(){returnSingletonInstance.INSTANCE;}}

3.5.2 优缺点

  • 优点:
    • 实现了懒加载
    • 线程安全
    • 只初始一次,效率高

3.5.3 涉及知识点

  1. 静态内部类的加载机制和生命周期
    推荐书籍:《深入理解Java虚拟机》

3.6 枚举

利用枚举机制,JVM帮助实现:

  • 加载的时候只有一个线程
  • 防止被反射的方式创建新的对象

3.6.1 实现方法

/** * @Description 单例示例 枚举 * @Author bigHao * @Date 2025/12/17 */publicenumSingleton{INSTANCE;publicvoidmockMethod(){System.out.println("use success.");}}

调用

/** * @Description 单例测试 枚举 * @Author bigHao * @Date 2025/12/17 */publicclassTest{staticvoidmain(){Singletoninstance=Singleton.INSTANCE;instance.mockMethod();}}

3.6.2 优缺点

  • 优点:
    • 线程安全
    • 防止被反射的方式创建新对象

3.6.3 涉及知识点

  1. 枚举类的加载机制和生命周期
    推荐书籍:《深入理解Java虚拟机》

4.源码体现

jdk中Runtime类使用的就是经典的单例模式(饿汉式)


  • 韩顺平 Java设计模式
  • H_D 【Java】单例模式双重检查锁(double-checked locking
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/28 0:25:26

01.需要了解的五种机器学习类型

需要了解的五种机器学习类型 [机器学习] (ML) 技术几乎可以推动所有行业的决策,从医疗保健到人力资源再到金融,以及计算机[视觉]、[大型语言模型] (LLM)、语音识别、自动驾驶汽车等各种应用场景。 然而,机器学习的影响力日益增长也并非没有复杂问题。支撑 ML 技术的验证和训…

作者头像 李华
网站建设 2025/12/18 21:58:51

02.什么是机器学习算法?

什么是机器学习算法? 机器学习算法是一种程序和数学逻辑,通过这种程序和逻辑,“机器”(人工智能 (AI) 系统)学习识别训练数据中的模式,并将这种模式识别应用于对新数据进行准确预测。机器学习算法是现代 AI 和数据科学的基本构建块,从简单的线性回归模型到尖端深度学习技…

作者头像 李华
网站建设 2025/12/18 21:56:06

基于元学习的 Agent 快速适应:少样本场景下的环境迁移学习

基于元学习的 Agent 快速适应&#xff1a;少样本场景下的环境迁移学习 一、背景与问题定义 在强化学习&#xff08;Reinforcement Learning, RL&#xff09;和智能 Agent 领域&#xff0c;一个长期存在的核心问题是&#xff1a;Agent 在新环境中往往需要大量交互样本才能学会有…

作者头像 李华
网站建设 2025/12/27 22:17:04

PayPal复制支付宝

出品I下海fallsea撰文I胡不知2025年12月15日&#xff0c;美国金融圈被一则声明打破平静——有“美版支付宝”之称的PayPal正式向联邦存款保险公司&#xff08;FDIC&#xff09;和犹他州金融机构部提交申请&#xff0c;计划成立名为“PayPal Bank”的工业贷款公司&#xff08;In…

作者头像 李华
网站建设 2025/12/18 21:53:55

【MongoDB实战】8.2 简易商品管理系统-核心功能实现

文章目录 简易商品管理系统(MongoDB + Flask 实现) 一、环境准备 1. 安装依赖 2. 配置文件(.env) 二、核心代码实现 整体结构 三、核心功能说明 1. 数据层(ProductDB) 2. 业务层(ProductService) 3. 接口层(Flask 路由) 四、测试示例 1. 启动服务 2. 接口测试(curl …

作者头像 李华