单例模式:双重效验锁的懒汉实现方式

2024-03-19 14:28

本文主要是介绍单例模式:双重效验锁的懒汉实现方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

单例模式:双重效验锁的懒汉实现方式

  • 单例模式
  • 饿汉模式实现
  • 懒汉模式实现
    • 改进1 (创建多个实例)
    • 改进2 (性能比较低)
    • 改进3 (volatile禁止指令重排序)

单例模式

单例模式顾名思义就是指实例化一个对象,通过把构造方法私有化来禁止创建实例。

饿汉模式实现

饿汉模式的特点是在类加载的时候就创建并初始化一个实例,实例在整个程序运行期间都是唯一的

public class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}

这里的getInstance()必须是静态方法,因为静态方法可以通过类名.方法名的方式调用,而非静态方法则要创建实例,这与我们单例模式的规则不相符。

懒汉模式实现

懒汉模式的特点是需要的时候再创建实例,实例在整个程序运行期间都是唯一的。

public class Singleton {private static Singleton instance = null;private Singleton() {}public static Singleton getInstance() {if (null == instance) {instance = new Singleton();}return instance;}
}

上面代码在单线程模式下是没问题的,但是在多线程模式下就会存在线程安全问题。
如果在首次创建实例,多个线程同时调用getInstance()方法,就有可能创建多个实例。

改进1 (创建多个实例)

我们可以进行对 getInstance() 方法进行加锁:

public class Singleton {private static Singleton instance = null;private Singleton() {}public static synchronized Singleton getInstance() {if (null == instance) {instance = new Singleton();}return instance;}
}

这样虽然解决刚刚线程安全的问题,但每次调用getInstance()方法都要加锁,增加不少的开销。
我们发现上面线程安全问题只存在于首次创建实例的情况,因此我们只需要对instance为空的时候单独处理即可。

改进2 (性能比较低)

instance为空的时候加锁,再判断一次是否为空即可:

public class Singleton {private static Singleton instance = null;private Singleton() {}public static Singleton getInstance() {if (null == instance) {synchronized (Singleton.class) {if (null == instance) {instance = new Singleton();}}}return instance;}
}

粗略的看上去好像没什么问题,实际上这里还有一个指令重排序的问题

通过查阅资料知道instance = new Singleton();这个代码在执行的时候实际是执行分3步骤执行:

memory = allocate(); //1.分配对象的内存空间
ctorInstance(memory); //2. 初始化对象
instance=memory; //3. 设置instance指向刚分配的内存地址

JVM在执行的时候可能就会优化成 1->3->2的顺序执行
可能导致在多线程环境下,还没执行2就已经被其他线程返回了一个刚分配的地址
同样存在线程安全问题,需要使用volatile关键字来禁止指令重排序

改进3 (volatile禁止指令重排序)

public class Singleton {//volatile 防止指令重排 和可见性private static volatile Singleton instance = null;private Singleton() {}public static Singleton getInstance() {//先判断对象是否已经实例化过,没有实例化才进入加锁代码if (null == instance) {//类对象加锁synchronized (Singleton.class) {//避免 singleTon== null时,第一个线程实例化后,进入阻塞状态的线程被唤醒后仍会进行实例化。if (null == instance) {instance = new Singleton();}}}return instance;}
}

以上就是线程安全的懒汉模式。

这篇关于单例模式:双重效验锁的懒汉实现方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/826286

相关文章

使用zip4j实现Java中的ZIP文件加密压缩的操作方法

《使用zip4j实现Java中的ZIP文件加密压缩的操作方法》本文介绍如何通过Maven集成zip4j1.3.2库创建带密码保护的ZIP文件,涵盖依赖配置、代码示例及加密原理,确保数据安全性,感兴趣的... 目录1. zip4j库介绍和版本1.1 zip4j库概述1.2 zip4j的版本演变1.3 zip4

RabbitMQ消息总线方式刷新配置服务全过程

《RabbitMQ消息总线方式刷新配置服务全过程》SpringCloudBus通过消息总线与MQ实现微服务配置统一刷新,结合GitWebhooks自动触发更新,避免手动重启,提升效率与可靠性,适用于配... 目录前言介绍环境准备代码示例测试验证总结前言介绍在微服务架构中,为了更方便的向微服务实例广播消息,

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种

python生成随机唯一id的几种实现方法

《python生成随机唯一id的几种实现方法》在Python中生成随机唯一ID有多种方法,根据不同的需求场景可以选择最适合的方案,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习... 目录方法 1:使用 UUID 模块(推荐)方法 2:使用 Secrets 模块(安全敏感场景)方法

Spring StateMachine实现状态机使用示例详解

《SpringStateMachine实现状态机使用示例详解》本文介绍SpringStateMachine实现状态机的步骤,包括依赖导入、枚举定义、状态转移规则配置、上下文管理及服务调用示例,重点解... 目录什么是状态机使用示例什么是状态机状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命

Spring Boot 结合 WxJava 实现文章上传微信公众号草稿箱与群发

《SpringBoot结合WxJava实现文章上传微信公众号草稿箱与群发》本文将详细介绍如何使用SpringBoot框架结合WxJava开发工具包,实现文章上传到微信公众号草稿箱以及群发功能,... 目录一、项目环境准备1.1 开发环境1.2 微信公众号准备二、Spring Boot 项目搭建2.1 创建

IntelliJ IDEA2025创建SpringBoot项目的实现步骤

《IntelliJIDEA2025创建SpringBoot项目的实现步骤》本文主要介绍了IntelliJIDEA2025创建SpringBoot项目的实现步骤,文中通过示例代码介绍的非常详细,对大家... 目录一、创建 Spring Boot 项目1. 新建项目2. 基础配置3. 选择依赖4. 生成项目5.

Linux线程之线程的创建、属性、回收、退出、取消方式

《Linux线程之线程的创建、属性、回收、退出、取消方式》文章总结了线程管理核心知识:线程号唯一、创建方式、属性设置(如分离状态与栈大小)、回收机制(join/detach)、退出方法(返回/pthr... 目录1. 线程号2. 线程的创建3. 线程属性4. 线程的回收5. 线程的退出6. 线程的取消7.

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序

Linux下删除乱码文件和目录的实现方式

《Linux下删除乱码文件和目录的实现方式》:本文主要介绍Linux下删除乱码文件和目录的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下删除乱码文件和目录方法1方法2总结Linux下删除乱码文件和目录方法1使用ls -i命令找到文件或目录