双检锁(DCL)下volatile的作用

由单例模式的优化,引出的java线程数据同步和类加载顺序知识点总结 由单例模式的优化,引出的java线程数据同步和类加载顺序知识点总结 摘要 几种单例模式的优缺点及其改进优化 DCL失效问题的原因以及解决 java中线程同步关键字final和volatile java内存屏障 java类加载顺序总结 饿汉单例 //片段1 class Singleton1{ private stat 阅读详情

先放代码:

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

然后来分析getInstance()每一步的作用

第一个if语句,用来确认调用getInstance()时instance是否为空,如果不为空即已经创建,则直接返回,如果为空,那么就需要创建实例,于是进入synchronized同步块。

synchronized加类锁,确保同时只有一个线程能进入,进入以后进行第二次判断,是因为,

对于首个拿锁者,它的时段instance肯定为null,那么进入new Singleton()对象创建,

而在首个拿锁者的创建对象期间,可能有其他线程同步调用getInstance(),那么它们也会通过if进入到同步块试图拿锁然后阻塞。

这样的话,当首个拿锁者完成了对象创建,之后的线程都不会通过第一个if了,而这期间阻塞的线程开始唤醒,它们则需要靠第二个if语句来避免再次创建对象。

以上就是双检索的实现思路,synchronized与第二个if即是用来保证线程安全与不产生第二个实例,也是Double_Checked_Lock由来。

那么volatile的作用体现在哪呢?

一开始我认为是volatile的同步性,因为要在首个拿锁者创建对象以后,立即保证instance的可见性,以让被唤醒的阻塞线程能够在第二个if语句的时候得到instance非空的结果。

但这个可见性其实是用synchronized来保障的,并不需要volatile来多此一举了。

后来才知道应该是避免指令重排序,说明如下

这里的指令重排序主要体现在instance = new Singleton()这条语句上了。

这条语句显然是个复合操作,可以简单分下,(已完成类加载 ,假设在堆上分配内存)

1.在堆中分配对象内存

2.填充对象必要信息+具体数据初始化+末位填充

3.将引用指向这个对象的堆内地址

那么,在完成1后,对象的大小和地址已经确定,因此,2和3其实存在指令重排序的可能。

并且可以看到,3的操作明显比2要少,那么如果让2与3一起执行,并且反应到具体的顺序上变成了1-3-2.

先完成3,引用变量instance先指向了在堆中给对象分配的空间,然后2仍在慢慢吞吞继续。

这时候,被synchronized挡在外面的阻塞线程其实是不会有什么影响的,因为一定会等到对象创建完,首个拿锁者才会释放锁。

那么关键是在,此刻如果在3完成而2未完成这个临界点,有一个新线程调用getInstance(),那么第一个if,会怎么样?

答案是因为第一个if没在同步块里,而此时instance已经非空,指向具体内存地址了,所以直接返回此时未完成初始化的instance实例

那么如果在Singleton里有个变量int number ,有个方法int getNumber()返回number,这时候调用

Singleton.getInstance().getNumber();

会怎样?

不知道,可能会报错,或者会得到错误结果,但这就是我能想到的volatile避免的情况了。

volatile修饰变量避免指令重排序,保证1-2-3按顺序来,这样即使在首个拿锁者未释放锁前,有线程切入,当它在第一个if处得到instance非空时,此时instance的初始化也一定已经完成。

因此这就是volatile在DCL的作用了。

ANSYS2022R1——安装源文件下载和安装教程——软件管家 14.当提示输入安装目录:#3时,①点击【浏览】,②选安装包解压后的【ANSYS2022R1_WINX64_Disk2】文件夹中【ANSYS2022R1_WINX64_Disk3】文件夹,③点击【选择文件夹】,④点击【OK】。12.当提示输入安装目录:#2时:①点击【浏览】,②选安装包解压后的【ANSYS2022.R1(64bit)】文件夹中的【ANSYS2022R1_WINX64_Disk2】文件夹,③点击【选择文件夹】,④点击【OK】。】②点击【OK】③点击【OK】。 阅读详情

相关推荐

VSAN闪存缓存磁盘故障处理指南-RAID0模式实战解析

本文详细解析了VSAN集群中RAID0模式下的闪存缓存磁盘故障处理全流程。通过模拟真实故障场景,从告警识别、数据重建策略到磁盘组重构,提供了手把手的实战操作指南,并深入探讨了RAID0缓存故障的独特影响与风险,为运维人员应对此类高性能存储架构的突发问题提供了专业解决方案。

assembly8low的博客 446

【Java】volatile

变量发生修改之后,由于线程工作内存中的值在此前已经加载,从而不会对变更操作做出相应变化,即私有内存和公共内存中变量不同步,进而导致数据不一致。解决的是变量读时的可见性问题,但无法保证原子性,对于多线程修改共享变量的场景必须使用加锁同步。只是保证从主内存加载到线程工作内存的值是最新的,也就是数据加载时是最新的。为例,不具备原子性,该操作是先读取值,然后写回一个新值,相当于原来的值加上。的写内存语义是直接刷新到主内存中,读的内存语义是直接从主内存中读取。写时,不论第一个操作是什么,都不能重排序。

qq_44544908的博客 434

在线绘制富集分析多组气泡图和单细胞分析marker基因矩阵气泡图

常规的GO或者KEGG通路富集分析结果通常以气泡图的形式展示,然而这个气泡图仅仅是一个比较的结果,如果想在一张图上展示多个比较的结果,就需要用到多组气泡图(图1,左侧)。 单细胞RNA-seq分析结果中,矩阵形式的气泡图可以很好地展示marker基因(X轴)在不同cluster(Y轴)中的表达情况(图1,右侧)。

微生信 3666

美团面试题:DCL单例模式需不需要volatile?

最近有粉丝收到美团的面试,去试了一试,结果没有过。然后在群里分享面试经历,其中有一个面试题《DCL 单例模式到底需不需要 volatile?》引起了大家的争议,今天我们一起来讨论讨论这个面...

xmt1139057136的专栏 1790

数字太大放不下,高精度来补,如何放下超大数字,以及进制转换,高精度真的超好玩。 洛谷1009,1015

想必大家都遇到过数字大小超过int类型范围的情况,是不是碰到int放不下的数字自然就会想到,long int,long long int,甚至unsigned long long int呢。但是有一些出题者就很可恶,偏要出一些连unsigned long long int也放不下的算法题,应对这些问题时,我们是否有相应的应对方法呢?答案是:当然有,高精度就是一种应对这种问题时很好的解决办法。相信你在看完这篇文章后能对高精度有着更深更好的理解。我会循序渐进的来讲,这样大家也更容易听懂。

2303_79329831的博客 1229

vasp计算练习1-Si

si的vasp训练流程

qq_41074165的博客 3299

DCL为什么要用volatile关键字?

先看一下DCL(双重检查锁模式)的示例代码: public class Singleton { //Singleton对象属性,加上volatile关键字是为了防止指定重排序,要知道singleton = new Singleton()拆分成cpu指令的话,有足足3个步骤 private volatile static Singleton singleton; //对外...

硅脂味咖啡的博客 3529

使用 Prometheus 监控 Spring Boot 应用

本文介绍了使用SpringBoot+Prometheus+Grafana实现应用监控的方案。首先在SpringBoot项目中集成Micrometer和Actuator组件,通过配置暴露Prometheus监控端点。接着配置Prometheus采集应用指标数据,并通过Grafana可视化展示。具体步骤包括:1)SpringBoot集成Micrometer;2)配置Prometheus抓取应用指标;3)安装Grafana并导入SpringBoot监控模板;4)展示JVM和业务指标。该方案可以实现对SpringB

蔡定努 431

Java Volatile关键字 DCL(双重检查锁)失效问题

Java Volatile关键字 DCL(双重检查锁)失效问题

qq_34503002的博客 433

【tessy】软件环境配置:Keil C51 Keil uVision UVSC (Default)

本文详细说明了tessy软件如何配置【Keil C51 Keil uVision UVSC (Default)】环境,具体操作步骤和注意事项

qq_37282365的博客 601

Python从0到100(二):Python语言介绍及第一个Pyhon程序

Python从0到100(二):Python语言介绍及第一个Pyhon程序。与C和Java比,Python的学习成本和难度曲线不是低一点,更适合新手入门,自底向上的技术攀爬路线。

拥有百余位万粉技术博主、200余位可合作代发博主,私域技术社群规模达千人,商务合作私信 5440

JUC 四. volatile 与内存屏障

目录一. volatile 基础二. 内存屏障三. volatile 与内存屏障四. volatile 变量的读写过程通过了解 volatile 的读写过程了解为什么不具备原子性五. 如何正确使用 volatile六. 总结 一. volatile 基础 前面我看了解了JMM内存模型,内存又分为主内存与本地内存(也就是缓存),线程读数据是主内存的,而修改数据是先修改缓存,然后由缓存刷出到主内存中,假设在刷出前其它线程进来可能读取到老数据,出现脏读等问题 volatile 基于JMM"先行发生原则happe

qq_29799655的博客 936

水与光的奇妙“切割之舞”:水导激光切割技术探秘

水导激光切割技术的诞生,是材料加工领域不断追求高精度、高质量加工的成果。传统激光切割技术在加工过程中,材料会因瞬间高温而产生热变形、热影响区大以及切割面粗糙等问题,这些弊端在对一些高精度、热敏性材料的加工中尤为突出 ,迫切需要一种新的技术来克服这些难题。水导激光切割技术的起源可以追溯到 20 世纪 80 年代。1986 年,德国公司 Aesculap-Werke AG 首次提出了将水流引入激光切割过程的创新想法,并制造出首代水导激光设备。不过,当时的技术尚处于雏形阶段,仅仅是在光纤出口添加了一小柱水流,激光

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 1673

[Java学习] 单例模式饿汉式双检锁/双重校验锁中的volatile

我们知道饿汉式的栓检锁写法,能在多线程的情况下保持高性能。但是很多小伙伴在查看资料的时候会发现,定义变量的时候有个volatile ,嗯?这是什么鬼?

qq_41792328的博客 318

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

深入理解JUC:第一章:volatile的三大特性

数据依赖性怎么理解?就是先有你爸再有你。假设我写的第20行代码,执行的时候不一定会从第一行执行到第20行,打个比方:参加高考做卷子,出题人给的题目,你不一定会从第一题做到最后一题,你可能会先把会的写了,其他有难度的题目最后写。代码案例1:再多线程环境下语句执行有1234和2134以及1324三种顺序,语句4不能重排后变成第一个,原因是什么说的数据依赖性,变量要先声明再使用。案例2:可以看到变量的值有二套,很恐怖的好吧,所以volatile需要禁止指令重排,确认最终变量的值。

2401_85407155的博客 899

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Java设计模式:单例模式双检锁,volatile

学习之前 作为Java萌新,真的很想吐槽。不懂的知识上网去搜,很多时候看到的是长篇大论,动不动就是底层,更离谱的是费劲九牛二虎之力看完了之后仍然是不明所以。因此决定把自己碰到的问题真正弄明白之后在这里记录下来,并以一种浅显易懂的方法表达出来,尽可能让部分人节省一些时间,当然对我自己也是一种提升。 一句话概括 单例模式 该类的对象只会被创建一个实例,多次获取到的都同一个栗子。 双检索 为了确保该对象的唯一性采取的措施。 volatile 多个线程访问同一变量情况下确保不会出错,不能保证线程安全

Java_haoren的博客 580

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

单例设计模式(DCL:双重检锁、懒汉式)

package com.jn.learning.javalearning.singleton; /********************************************************************************************** * * * Written by TankPush (Jn) * * Description: * DCL双重检测单例 * volatile: ①保证线程可见性 ②防止指令重排序 * 线程安全 * * *

JnYoung的博客 505

Java双检锁单例:volatile如何防止半成品对象与指令重排序

在Java并发编程中,单例模式与延迟初始化常涉及线程安全与内存可见性问题。双检锁(DCL)通过两次null检查与synchronized块减少锁开销,但对象创建并非原子操作,指令重排序可能导致线程获取到未初始化完成的半成品对象。volatile关键字通过插入内存屏障禁止重排序,并保证可见性,确保实例引用赋值前构造方法已执行完毕。这一机制在高并发场景下至关重要,广泛应用于缓存、配置管理等单例初始化场景。本文深入字节码层面,结合可复现实验,剖析volatile在DCL中的核心作用,并对比静态内部类、枚举等替代方

weixin_34072296的博客 114

手写单例模式:不会就尴尬了

手写单例模式 介绍: 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 主要解决:一个全局使用的类频繁地创建与销毁。 何时使用:当您想控制实例数目,节省系统资源的时候。 如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。 关键代码:构造函数是私有的。 优点: 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。 2、避免对资源的多重占用(比如写文件操作)。 缺点: 没有接口,不能继承,与单一职责原则冲突

weixin_44587820的博客 5783

java关键字_Java中Volatile关键字

戳上方蓝字 “给自己一个smile” 关注我 并 置顶星标! 你的关注意义重大!目录 1. JMM内存模型概述2.volatile 关键字 3. 内存模型之重排序 4. 单列模式DCL分析一JMM内存模型概述1. 概述Java虚拟机规范中试图定义一种Java内存模型JMM(Java Memory Model)来屏蔽掉各种硬件和操作系统的内存...

weixin_39637545的博客 68

ConcurrentProgramming:volatile/构造方法溢出/禁止重排序

一、64位写入的原子性(Half Write) 如,对于一个long型变量的赋值和取值操作而言,在多线程场景下,线程A调用set(100),线程B调用get(),在某些场景下,返回值可能不是100。 public class MyClass { private long a = 0; // 线程A调用set(100) public void set(long a) { this.a = a; } // 线程B调用get(),返回值一定是100吗? pu

chuanchengdabing的博客 277

中改变了值但是数据没有刷新_Java中Volatile关键字

戳上方蓝字 “给自己一个smile” 关注我 并 置顶星标! 你的关注意义重大!目录 1. JMM内存模型概述2.volatile 关键字 3. 内存模型之重排序 4. 单列模式DCL分析一JMM内存模型概述1. 概述Java虚拟机规范中试图定义一种Java内存模型JMM(Java Memory Model)来屏蔽掉各种硬件和操作系统的内存...

weixin_35649491的博客 633

Java双检锁与volatile:从指令重排到单例模式最佳实践

在Java并发编程中,线程安全与内存可见性、有序性密切相关。volatile关键字通过内存屏障禁止指令重排,确保共享变量的修改对其他线程立即可见。这一机制在延迟初始化场景中尤为关键,例如单例模式的双检锁实现。若缺少volatile,对象创建过程中的指令重排可能导致其他线程获取到未初始化完成的对象,引发隐蔽的并发缺陷。双检锁结合volatile,既实现了延迟加载,又保证了高性能与线程安全,广泛应用于需要延迟初始化且兼顾性能的框架与中间件中。

weixin_29587015的博客 176

java单例模式的各种实现以及DCL的注意事项

java单例模式实现方式大全 DCL

zhang_qing_yun的博客 360

单例、懒汉模式的思路整理

采用双检锁/双重校验锁(DCL,即 double-checked locking) package single; /** * 懒汉模式的单例 * * @author 苏察哈尔丶灿 */ public class SingleCase { // 类的唯一实例 private static SingleCase instance = null; // 构造方法私有化,阻止外部生成对象 private SingleCase() { } /** * 第一种做法 *

weixin_41826641的博客 188

设计模式-单例模式

单例模式(SingletonPattern)属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。一个全局使用的类频繁地创建与销毁。当您想控制实例数目,节省系统资源的时候。判断系统是否已经有这个单例,如果有则返回,如果没有则创建。没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。......

Mamba Out 202
上一篇: 秋招准备-Java-JVM-内存区域+GC
下一篇: 秋招准备-Java-并发编程-多线程基础(一)
LLLLLin0
博客等级 码龄11年 17粉丝 26原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值