单例模式懒汉式

news/2025/2/13 6:19:54/
// 懒汉式
public class Singleton {// 延迟加载保证多线程安全Private volatile static Singleton singleton;private Singleton(){}public static Singleton getInstance(){if(singleton == null){synchronized(Singleton.class){if(singleton == null){singleton = new Singleton();}}}return singleton;}
}
  1. 使用 volatilevolatile 修饰符确保了变量的可见性和防止指令重排序。在懒汉式单例模式中,当多个线程访问 getInstance() 方法时,如果不使用 volatile,由于指令重排序的问题,可能会导致一个线程获取到一个半初始化状态的对象。通过使用 volatile 关键字,可以确保变量在多线程环境下的可见性,也就是当一个线程修改了 instance 变量的值,其他线程能够立即看到最新的值。

  2. 第一层 if (singleton == null):这是一种最基本的检查,用于防止多个线程同时创建实例。如果 singleton 已经被创建,后续的线程不需要再进入同步块,从而提高性能。

  3. synchronized:在 getInstance() 方法中使用 synchronized 关键字是为了确保在多线程环境下只有一个线程可以进入临界区(也就是同步块),从而避免多个线程同时创建实例。这种方式会带来一定的性能开销,因为每次调用 getInstance() 都需要获取和释放锁。

  4. 第二层 if (singleton == null):这是一种双重检查锁定,用于确保只有一个线程能够在同步块内创建实例。在第一次检查中,如果 singleton 不为 null,那么后续线程不会进入同步块,从而避免了不必要的锁竞争。只有当 singleton 为 null 时,才会进一步检查并创建实例。

总的来说,这种方式结合了懒加载和线程安全的特性,确保只有在需要时才创建实例,并且在多线程环境下能够正确地工作。但需要注意的是,虽然这是一种有效的懒汉式单例模式实现,但在某些情况下,可能会有更好的替代方案,如使用静态内部类来实现单例。这种方式不仅线程安全,而且具有良好的性能。

为什么进入同步块之后还要判断?

进入同步块之后再次判断的目的是为了避免多个线程在同一时刻创建多个实例。虽然同步块可以确保只有一个线程可以进入临界区(即同步块),但在多线程环境中,可能会出现以下情况:

  1. 线程 A 进入了同步块,此时 instance 仍然为 null,线程 A 开始创建实例。
  2. 此时线程 B 也通过了第一次检查,因为线程 A 还没有完成实例的创建,所以 instance 仍然为 null
  3. 线程 B 也进入了同步块,如果没有第二次检查,它将继续创建一个新的实例,这就导致了多个实例的创建。

通过在同步块内再次检查 instance 是否为 null,可以确保只有一个线程在同一时刻创建实例。如果线程 A 创建了实例,线程 B 进入同步块后会发现 instance 已经不为 null,因此不会再次创建实例,从而避免了多个实例的产生。

这就是双重检查锁定的思想,它既能够实现懒加载(即只有在需要时才创建实例),又能够确保线程安全。这种方式在性能上相对较好,因为只有在第一次创建实例时才需要进入同步块,后续的线程都可以避免同步块的开销。


http://www.ppmy.cn/news/1155154.html

相关文章

嵌入式实时操作系统的设计与开发 (启动过程学习)

b Reset; b Undef; b SWI; b PreAbort; b DataAbort; b . ;保留 b IRQ; b FIQ;建立异常向量表的过程,其中第一个指令通常都是存放在主存的零地址的。 异常向量表存放的全是汇编跳转指令,这些指令从主存的零地址(0x0)开始连续存储在…

前端页面布局之【响应式布局】

目录 🌟前言🌟优点🌟缺点🌟media兼容性🌟利用CSS3-Media Query实现响应式布局🌟常见的媒体类型🌟常见的操作符🌟属性值🌟设备检测🌟响应式阈值选取&#x1f3…

GOPATH和Go Modules

Go语言的包依赖管理经历了几次变革 最早的时候,Go所依赖的所有的第三方库都放在GOPATH目录下面 go v1.5引入vendor模式,如果项目目录下有vendor目录,那么go工具链会优先使用vendor内的包进行编译、测试等 go v1.11开始,引入Go …

王阳明学习笔记

王阳明(一)溺 少年时五溺 任侠、骑射、辞章、神仙、佛氏。 始归正于圣贤之习。 今天的人们需要王阳明吗 35岁王阳明的至暗时刻,投江之前因言遭到了宦官的迫害,熬过酷刑,被贬放,留下了告终词和两首绝命诗。 1472王阳明出生在浙江…

Linux | 关于入门Linux你有必要了解的指令

目录 前言 1、ls指令 2、pwd指令 3、cd指令 4、touch指令 5、stat指令 6、mkdir指令 7、rmdir 与 rm指令 8、man指令 9、cp指令 10、mv指令 11、cat指令 (1)输入重定向 (2)输出重定向与追加重定向 12、less指令 1…

Yakit工具篇:简介和安装使用

简介(来自官方文档) 基于安全融合的理念,Yaklang.io 团队研发出了安全领域垂直语言Yaklang,对于一些无法原生集成在Yak平台中的产品/工具,利用Yaklang可以重新编写 他们的“高质量替代”。对于一些生态完整且认可度较高的产品,Y…

嵌入式实时操作系统的设计与开发(轮询系统学习)

轮询系统具有以下工作特点:系统完成一个轮询的时间取决于循环中需要执行的函数个数。此外,轮询的次序是静态固定的,在运行时不能进行动态调整。 典型系统 许多工业线程网络中,由于需要控制的设备较多、相互距离又较远&#xff0…

LeetCode每日一题:1488. 避免洪水泛滥(2023.10.13 C++)

目录 1488. 避免洪水泛滥 实现代码与解析: 贪心 原理思路: 1488. 避免洪水泛滥 题目描述: 你的国家有无数个湖泊,所有湖泊一开始都是空的。当第 n 个湖泊下雨前是空的,那么它就会装满水。如果第 n 个湖泊下雨前是…