当前位置: 首页 > news >正文

单例模式的理解

目录

    • 单例模式
      • 1.饿汉式(线程安全)
      • 2.懒汉式(通过synchronized修饰获取实例的方法保证线程安全)
      • 3.双重校验锁的方式实现单例模式
      • 4.静态内部类方式实现单例模式【推荐】

单例模式

1.饿汉式(线程安全)

package 并发的例子.单例模式;
// 饿汉式单例模式(天然线程安全,但不支持懒加载)
public class Singleton1 {// 1. 静态成员变量:在类加载阶段(JVM层面)就完成实例化//    - static保证全局唯一一份,类加载时由JVM保证线程安全(仅初始化一次)//    - final修饰防止被意外修改,确保实例不可变private static final Singleton1 INSTANCE = new Singleton1();// 2. 私有构造方法:禁止外部通过new创建实例,保证单例唯一性private Singleton1() {}// 3. 公开静态方法:提供全局访问点,直接返回已初始化的实例public static Singleton1 getInstance() {return INSTANCE;}// 测试:验证多次获取的是否为同一实例public static void main(String[] args) {Singleton1 instance1 = Singleton1.getInstance();Singleton1 instance2 = Singleton1.getInstance();Singleton1 instance3 = Singleton1.getInstance();// 输出均为true,证明所有引用指向同一个实例System.out.println(instance1 == instance2);System.out.println(instance2 == instance3);System.out.println(instance1 == instance3);}
}

2.懒汉式(通过synchronized修饰获取实例的方法保证线程安全)

package 并发的例子.单例模式;
// 懒汉式(通过synchronized修饰获取实例的方法保证线程安全,但由于整个方法加锁,效率不高性能略差)
public class Singleton2 {// 定义实例对象引用(仅声明,未创建实例,实现延迟初始化的基础)private static Singleton2 instance;// 私有构造方法,防止其他类通过new关键字创建实例,确保单例唯一性private Singleton2() {}// 公开的静态方法,用于获取单例实例// 使用synchronized修饰方法:保证多线程环境下,同一时间只有一个线程能进入方法,避免创建多个实例public static synchronized Singleton2 getInstance() {// 懒加载(延迟加载):只有当首次调用getInstance()时,才会创建实例对象,节省初始化资源if (instance == null) {instance = new Singleton2();}return instance;}public static void main(String[] args) {// 测试单例模式:多次获取实例,验证是否为同一对象Singleton2 s1 = Singleton2.getInstance();Singleton2 s2 = Singleton2.getInstance();Singleton2 s3 = Singleton2.getInstance();// 通过hashCode判断是否为同一对象(同一对象的hashCode相同)System.out.println(s1.hashCode());System.out.println(s2.hashCode());System.out.println(s3.hashCode());}
}

3.双重校验锁的方式实现单例模式

package 并发的例子.单例模式;// 用双重校验锁的方式实现单例模式
// 简单说就是:保证整个程序里只有这一个类的对象,而且线程安全、用到时才创建、效率还不错
public class Singleton3 {// 存单例对象的地方,整个程序就这一个// volatile关键字有两个超能力:// 1. 防止"指令插队":创建对象的时候步骤必须是【分配内存→初始化对象→给instance赋值】,不能乱序// 2. 保证"看得见":一个线程把对象创建好赋值给instance了,其他线程马上能看到,不会因为缓存犯傻private static volatile Singleton3 instance;// 把构造方法藏起来,不让外面用new创建对象// 这样就只能通过我们写的getInstance方法来拿对象,保证只有一个private Singleton3() {}// 对外提供的拿单例对象的方法,全局就这一个入口public static Singleton3 getInstance() {// 第一次检查:先快速看看有没有对象// 要是已经有了,直接返回,不用走后面的复杂流程,省时间if (instance == null) {// 加锁排队:多个线程同时到这的时候,只能一个一个来// 锁的是整个类(Singleton3.class),保证全局就这一把锁synchronized (Singleton3.class) {// 第二次检查:进了锁之后再看一眼// 防止多个线程都通过第一次检查后,进来重复创建对象// 要是不检查,线程1创建完,线程2进来又创建,就不是单例了if (instance == null) {// 真正创建对象的地方// 要是没加volatile,可能出现"对象还没初始化好,就把半成品给instance"的情况// 加了volatile就保证步骤是【分配内存→初始化对象→给instance赋值】,稳稳的instance = new Singleton3();}}}// 返回单例对象,不管哪个线程来拿,都是同一个return instance;}
}

4.静态内部类方式实现单例模式【推荐】

package 并发的例子.单例模式;
// 静态内部类方式实现单例模式【推荐】
// 特点:线程安全(依托类加载机制) + 懒加载(真正用到实例时才加载) + 简洁高效
public class Singleton4 {// 1. 私有化构造方法//    作用:禁止外部通过 new Singleton4() 创建对象,确保对象只能通过 getInstance() 获取private Singleton4() {}// 2. 静态内部类:SingletonHolder//    特点://    - 静态内部类不会随着外部类加载而加载,属于「懒加载」private static class SingletonHolder {// 3. 静态内部类中定义单例对象//    - final 保证实例不可变,一旦赋值无法修改//    - 类加载时创建实例,由 JVM 保证线程安全(多线程下不会重复创建)private static final Singleton4 INSTANCE = new Singleton4();}// 4. 对外提供获取单例的方法public static Singleton4 getInstance() {// 调用此方法时,才会触发 SingletonHolder 的类加载// 类加载过程中,JVM 会创建 INSTANCE,且保证全局唯一、线程安全return SingletonHolder.INSTANCE;}public static void main(String[] args) {Singleton4 s1 = Singleton4.getInstance();Singleton4 s2 = Singleton4.getInstance();Singleton4 s3 = Singleton4.getInstance();// 通过hashCode判断是否为同一对象(同一对象的hashCode相同)System.out.println(s1.hashCode());System.out.println(s2.hashCode());System.out.println(s3.hashCode());}
}
1.为什么用静态内部类?
静态内部类 SingletonHolder 是 “懒汉”:外部类 Singleton4 加载时,它不会跟着加载,真正调用 getInstance() 时才会加载,实现 “用的时候再创建”(懒加载)。
2.线程安全怎么保证?
JVM 加载类时,会保证 “同一类全局只加载一次”,且加载过程是线程安全的(多线程同时调用 getInstance()SingletonHolder 也只会加载一次)。
因此 INSTANCE 只会创建一次,天然线程安全。
3.对比其他单例的优势
比 “饿汉式” 懒:饿汉式类加载时就创建实例,静态内部类做到了 “用的时候才创建”。
比 “懒汉式(同步方法)” 高效:无需手动加锁,依托 JVM 类加载机制保证线程安全,性能更好。
4.适合场景
需要 懒加载(延迟初始化),且希望 线程安全、代码简洁 的场景。
推荐作为日常开发中 “单例模式” 的首选方案,兼顾性能和安全性。

http://www.dtcms.com/a/329033.html

相关文章:

  • 【密码学实战】国密TLCP协议简介及代码实现示例
  • FemalePower项目学习笔记
  • ASP.NET 上传文件安全检测方案
  • 怎么使用python查看网页源代码
  • FreeRTOS创建多线程详解
  • 基于微信小程序的工作日报管理系统/基于asp.net的工作日报管理系统
  • USB批量传输数据为端点最大数据包(比如512字节)整数倍时接收端收不到数据
  • Linux系统文件完整性检查工具AIDE在生产环境中推送钉钉告警
  • 音视频处理新纪元:12款AI模型的语音转录和视频理解能力横评
  • MySQL 到 ClickHouse 明细分析链路改造:数据校验、补偿与延迟治理
  • 前端css学习笔记4:常用样式设置
  • 2025盛夏AI热浪:八大技术浪潮重构数字未来
  • RC4算法实现
  • 前后端分离项目在云服务器的部署
  • java实现sql解析器 JSQLParser
  • 16-docker的容器监控方案-prometheus实战篇
  • 30 HTB Soccer 机器 - 容易
  • 【Android】四种不同类型的ViewHolder的xml布局
  • 双写一致性问题如何解决?
  • Python 元类基础:从理解到应用的深度解析
  • 机器翻译:学习率调度详解
  • 小电视视频内容获取GUI工具
  • 长篇音频制作(小说自动配音)完整教程
  • 嵌入式 - linux软件编程: 目录 IO及时间相关的函数接口
  • 《Python学习之基础语法1:从零开始的编程之旅》
  • Verilog功能模块--SPI主机和从机(02)--SPI主机设计思路与代码解析
  • 电商项目微服务架构拆分实战
  • 使用TexLive与VScode排版论文
  • 内容索引之word转md工具 - markitdown
  • 华为 HCIE 大数据认证中 Linux 命令行的运用及价值