单例模式为什么要用Volatile关键字

单例模式为什么需要volatile关键字? 在单例模式中,为了保证效率的同时,保证线程安全,我们会了解这一段代码 双重校验锁 public class SingletonLazy { private volatile static SingletonLazy data; private SingletonLazy(){ System.out.println("初始化"); } public SingletonLazy getData() { if (data == null) { 阅读详情

线程安全的单例模式常见写法是双重检查加锁。代码如下:


class Singleton{

    private volatile static Singleton singleton;



    private Singleton(){}       

    public static Singleton getInstance(){       

        if(singleton == null){                  // 1

            synchronized(Singleton.class){      // 2

                if(singleton == null){          // 3

                    singleton = new Singleton(); // 4

                }

            }

        } 

        return singleton;           

    }

}

双重检查加锁的单例模式代码上就比较复杂,尤其体现在getInstance方法上,包括两次检查singleton是否是null,一次加锁,singleton用关键字volatile修饰。为什么写一个单例如此复杂呢?

首先是懒汉模式,实例的初始化延迟到getInstance方法中,为了保证只会生成一个实例,要先判断singleton是否已经初始化,如果已经初始化了,就返回singleton,没有的话就创建对象。这就是1的作用。如果是单线程的情况,这样就够用了。

在多线程的情况下,只有1,没有2,3,就可能导致创建多个实例。例如,线程A和线程B调用getInstance方法,线程A先判断了1,然后时间片结束了,切换到线程B,线程B判断1,然后创建了singleton。时间片有切会线程A,线程A创建实例。这样就线程A和线程B就分别创建了一个实例了。破坏了单例的结构。

为了解决这个问题,加了synchronized保证只有一个线程进入临界区。那只有2,没有3,可以吗?还是考虑和前面一模一样的场景,这次线程A和线程B都判断了1了,进入2,线程A先进入临界区,线程B发现线程A进入了临界区,就挂在了Singleton.class等等待队列中,等待线程A执行完成。线程A继续执行,创建了一个singleton实例。退出了临界区。然后线程B被唤醒,进入临界区,又创建了一个singleton实例。结果又创建了两个singleton实例。

所以3的作用很明显了。在上面例子中,如果线程B发现实例已经被创建了(singleton不等于null),就直接退出临界区了。那1和3的作用似乎有点重合了,1似乎就不是必须了。2,3确实就足够保证单例了。但是加锁是比较消耗资源的,1就是为了减少资源的消耗。

最后,这么看来1,2,3,4就足以保证单例了。那为什么需要加volatile呢?volatile就牵扯到指令重排序的问题了。

要理解为什么要加volatile,首先要理解new Singleton()做了什么。new一个对象有几个步骤。1.看class对象是否加载,如果没有就先加载class对象,2.分配内存空间,初始化实例,3.调用构造函数,4.返回地址给引用。而cpu为了优化程序,可能会进行指令重排序,打乱这3,4这几个步骤,导致实例内存还没分配,就被使用了。

再用线程A和线程B举例。线程A执行到new Singleton(),开始初始化实例对象,由于存在指令重排序,这次new操作,先把引用赋值了,还没有执行构造函数。这时时间片结束了,切换到线程B执行,线程B调用new Singleton()方法,发现引用不等于null,就直接返回引用地址了,然后线程B执行了一些操作,就可能导致线程B使用了还没有被初始化的变量。

加了volatile之后,就保证new 不会被指令重排序。

至此,这就是一个完整的懒汉模式—>线程安全的->双重检查加锁单例模式。

推荐另一种单例模式的写法:

class Singleton{
    private Singleton(){}
    
    private static class LazySomethineHolder{
        public static Singleton singleton = new Singleton();
    }

    public static Singleton getInstance(){
        return LazySomethineHolder.singleton;
    }
}

 

【为什么单例一定要加 volatile?】 阅读详情

相关推荐

python语言下使用opencv接口cv2.VideoCapture()接口调用海康机器人工业相机

文章目录 目录 文章目录 前言 一、opencv接口介绍 二、调用海康机器人工业相机 1.使用海康机器人工业相机的前提 2.调用海康机器人工业相机进行显示 3.调用海康机器人工业相机进行存图 4.调用海康机器人工业相机存视频 5.调用海康机器人工业相机进行简单图像处理 总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇文章正文内容,下.

qq_39570716的博客 1万+

面试突击51:为什么单例一定要加 volatile?

.作者 | 磊哥来源 | Java面试真题解析(ID:aimianshi666)转载请联系授权(微信ID:GG_Stone)单例模式的实现方法有很多种,如饿汉模式、懒汉模式、静态内部类和枚举等,当面试官问到“为什么单例模式一定要加 volatile?”时,那么他指的是为什么懒汉模式中的私有变量要加 volatile?懒汉模式指的是对象的创建是懒加载的方式,并不是在程序启...

磊哥聊Java 4031

稳定双共轭梯度法BiCGSTAB流程

稳定双共轭梯度法BiCGSTAB流程

abner361的博客 1154

【面试题】为什么单例一定要加 volatile?【懒汉模式为什么要用volatile】【volatile的作用】

使用 volatile 可以解决内存可见性问题和防止指令重排序,我们在单例模式中使用 volatile 主要是使用 volatile 的后一个特性(防止指令重排序),从而避免多线程执行的情况下,因为指令重排序而导致某些线程得到一个未被完全实例化的对象,从而导致程序执行出错的情况。

蓝天it(让亿万孩子在蓝天下共享优质教育) 1273

CVPR 2027 投稿规划:基于近3年录用率与截稿周期的5步时间管理法

本文为计算机视觉研究者提供CVPR 2027投稿的完整规划指南,基于近三年录用率与截稿周期数据,提出五步时间管理法。涵盖选题策略、实验设计、论文写作、同行评审到最终提交的全流程优化,特别针对CVPR日益激烈的竞争环境(2024年投稿量达11532篇,录取率仅23.6%)提供实用解决方案,帮助研究者提升投稿成功率。

weixin_34079177的博客 1143

等保三级-MySQL 安全加固实战指南

本文详细介绍了MySQL数据库在等保三级要求下的安全加固实战指南,涵盖身份鉴别、访问控制、安全审计、网络传输安全、入侵防范和数据完整性等关键领域。通过具体配置示例和实战经验,帮助用户有效提升MySQL数据库的安全防护能力,满足等保三级合规要求。

weixin_29197835的博客 183

双重检查锁单例模式为什么要用volatile关键字?

原文链接 前言 从Java内存模型出发,结合并发编程中的原子性、可见性、有序性三个角度分析volatile所起的作用,并从汇编角度大致说了volatile的原理,说明了该关键字的应用场景;在这补充一点,分析下volatile是怎么在单例模式中避免双检锁出现的问题的。 并发编程的3个条件 1 原子性:要实现原子性方式较多,可用synchronized、lock加锁,AtomicInteger等,但v...

kaven 6447

【NVIDIA驱动的顽固问题】---- /dev/sdax:clean,xxx/xxx files,xxx/xxx blocks ---- 最全解决方法

本文的意义在于整理总结关于此问题的全部解决方法,希望能给大家节约时间。

lc1852109的博客 3124

单例模式下为什么一定要加volatile关键字

有一道面试题,单例模式已经双重检查锁定(Double-Check-Lock)了,要不要加volatile关键字。以下是双重检查锁定来实现单例模式代码 public class DoubleCheckLock { private static DoubleCheckLock INSTANCE; private DoubleCheckLock() { } public static DoubleCheckLock getInstance() { if (I

程序员二胖 1437

抖音风控参数‘bd-ticket-guard-client-data’深度解析:从X.509证书到请求签名的完整链路

本文深度解析抖音风控参数‘bd-ticket-guard-client-data’的技术实现,从X.509证书体系到请求签名的完整安全链路。通过Python代码示例,揭示证书生成、签名算法及票据封装等核心机制,帮助开发者理解现代平台风控系统的多层防御架构设计。

weixin_42525738的博客 432

Python爬虫实战:基于Scrapy和Playwright的深交所数据采集

本文将详细介绍如何使用Python最新技术栈(Scrapy框架结合Playwright浏览器自动化)爬取深圳证券交易所(www.szse.cn)的公开数据。文章包含完整项目搭建、反爬策略应对、数据解析存储等全流程实现,并附详细代码示例和性能优化建议。python复制下载# 上市公司基本信息# 财务数据revenue = scrapy.Field() # 营业收入net_profit = scrapy.Field() # 净利润eps = scrapy.Field() # 每股收益。

2201_76125261的博客 949

Java中volatile关键字的使用以及在单例模式下的使用

单例模式(Singleton Pattern)是一种设计模式,旨在保证一个类只有一个实例,并提供一个全局访问点来获取该实例。换句话说,单例模式确保在整个应用程序生命周期内某个类只有一个对象实例存在,且该实例可以在任何地方被访问。

2201_75420324的博客 2103

基于FPGA的UDP 通信(六)

本文基于FPGA和MATLAB对千兆以太网通信模块UDP数据发送(FPGA发送)进行联合调试。

记录所学,分享知识,结识挚友 4729

Java volatile关键字和单例模式

在看单例模式的代码时,发现单例模式有一种实现方法中出现了volatile 关键字,这里就有了疑问: 为什么要使用volatile关键字?? volatile关键字与多线程中的双重检查有什么关系?? volatile与synchronized有什么关系??? 单例模式的八种实现代码,参考以下博文: 链接:https://www.cnblogs.com/zhaoyan0...

统木木的博客 529

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

单例模式中volatile关键字的作用

什么是单例模式 单例模式指的是,保证一个类只有一个实例,并且提供一个可以全局访问的入口。 为什么需要使用单例模式 那么我们为什么需要单例呢?其中一个理由,那就是为了节省内存、节省计算。因为在很多情况下,我们只需要一个实例就够了,如果出现更多的实例,反而纯属浪费。 下面我们举一个例子来说明这个情况,以一个初始化比较耗时的类来说,代码如下所示: public class ExpensiveResource { public ExpensiveResource() { field1 = /

大叶子不小的博客 1410

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

一文带你搞懂DCL单例模式为什么要加volatile关键字

一文带你搞懂DCL单例模式为什么要加volatile关键字

weixin_45642975的博客 979

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Volatile关键字的底层实现原理以及单例模式中使用Volatile关键字的原因

Volatile关键字在多处理器开发环境中或者多线程环境下,保证共享变量的可见性。 可见性:当一个线程修改共享变量的值之后,其它线程可以立即读取到它修改的值。 如果 volatile 使用得当的话,它会比 synchronized 的成本更低,因为它不会造成线程的阻塞,也就不会导致上下文切换和调度,所以性能更好,开销更低。 Volatile的定义 Java 编程语言允许线程访问共享变量,为了确保共...

qq_33898680的博客 368

volatile关键字在单例模式(双重校验锁)中的作用

本文主要讲述了Java单例模式之双重校验锁中volatile关键字的作用。 更多文章欢迎访问我的个人博客–>幻境云图 上篇文章Java设计模式(一)–单例模式中讲了Java单例模式的几种写法,其中懒汉式和双重校验锁方式写法如下: 1. 懒汉式 public class Singleton { private static Singleton instance; ...

探索云原生 1万+

一个单例模式中volatile关键字引发的思考

对于JMM的happens-before规则,即对一个volatile修饰的变量的写操作,happens-before随后对这个变量的读操作。而如果我们使用一个基于句柄方式访问对象的编译器(如Symantec JIT),不加volatile关键字可能会导致重排序,返回一个未初始化完成的实例。,其中说到:如果使用Symantec JIT(一个基于句柄方式访问对象的编译器),它编译出来的代码就会发生上述的重排序。// 给客户端调用的,如果初始化未完成,应该返回false,如果完成,返回true。

Java程序员的知识博客 1037

volatile关键字在单例模式中的应用

这几天在研究volatile关键字,有看书,上网找博客,本来看的还挺好的理解的,但是卡在了一个地方,就是单例模式中懒汉模式使用Double Check里面的volatile的作用原理弄糊涂了。不同地方有不同的说法,最后终于理清了。 关键字volatile可以说是Java虚拟机提供的最轻量的同步机制,但是它并不容易完全被正确、完整地理解,以至于许多程序员都不习惯去使用,遇到需...

我爱编程持之以恒 2370

Volatile关键字以及单例模式双重检测锁

Volitale关键字和单例模式双重检测锁 volatile: volatile关键字是在多线程环境下我们用来保证变量的可见性以及有序性用来修饰该变量的关键字 先来看一段代码,这段代码中我们希望A线程能够第一时间读取到变量value的改变并且B线程能够去输出当前value的最新值 public class TestDemo10 { public static int value=0; public static void main(String[] args) {

qq_43716944的博客 382

单例模式——Double Check 双重校验锁实现方式为什么要加volatile关键字

单例模式——Double Check 双重校验锁实现方式为什么要加volatile关键字 单例模式双重校验锁实例: public class Singleton { private static volatile Singleton singleton = null; private Singleton() {} public static Singleton getInstance(){ //第一次校验singleton是否为空 if(

newbiee的博客 749

volatile关键字、ThreadLocal关键字、单例模式

接下来t2获得锁,创建实例。对于线程池里面不会销毁的线程,里面总会存在着《threadlocal,localVarible》的强引用,因为final static修饰的ThreadLocal并不会释放,而ThreadLocalMap对于key虽然是弱引用,但强引用没有释放,弱引用会一直存在,同时创建的localVarible对象也不会释放造成内存泄漏;为提高执行效率,在不影响最终执行结果的前提下,代码在编译成字节码的时候有可能进行指令重新排序,这在单线程情况下是没有问题的,但是在多线程的情况下会出现问题。

linxi438的博客 399
上一篇: SpringBoot用Jest连接ElasticSearch打成jar包出现找不到 http://localhost:9200的错误
下一篇: 模板方法设计模式
qq_34412985
博客等级 码龄11年 143粉丝 983原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值