介绍

双重校验锁是单例模式中,饿汉式的一种实现方式。因为有两次判空校验,所以叫双重校验锁,一次是在同步代码块外,一次是在同步代码块内。

为什么在同步代码块内还要再检验一次?

第一个if减少性能开销,第二个if避免生成多个对象实例。

现有三个线程A,B,C,假设线程A和线程B同时调用getSingleton()时,判断第一层if判断都为空,这时线程A先拿到锁,线程B在代码块外层等待。线程A进行第二层if判断,条件成立后new了一个新对象,创建完成,释放锁,线程B拿到锁,进行第二层if判断,singleton不为空,直接返回singleton释放锁,避免生成多个对象实例。线程线C调用getSingleton时第一层判断不成立,直接拿到singleton对象返回,避免进入锁,减少性能开销。

为什么要用volatile关键字?

singleton = new Singleton();这行代码并不是一个原子指令,可能会在JVM中进行指令重排;

new 实例背后的指令,我们通过使用 javap -c指令,查看字节码如下:

   // 创建 Singleton 对象实例,分配内存
0: new #5
// 复制栈顶地址,并再将其压入栈顶
3: dup
// 调用构造器方法,初始化 Singleton对象
4: invokespecial #6 // Method "<init>":()V
// 存入局部方法变量表
7: astore_1

从字节码可以看到创建一个对象实例,可以分为三步:

(1)分配对象内存(给singleton分配内存)。

(2)调用构造器方法,执行初始化(调用 Singleton 的构造函数来初始化成员变量)。

(3)将对象引用赋值给变量(执行完这步 singleton 就为非 null 了)。

在 JVM 的即时编译器中存在指令重排序的优化。指令重排并不影响单线程内的执行结果,但是在多线程内可能会影响结果。也就是说上面的2和3的顺序是不能保证的,但是并不会重排序 1 的顺序,因为 2,3 指令需要依托 1 指令执行结果。最终的执行顺序可能是 1-2-3 也可能是 1-3-2。

1-3-2的情况

上面多线程执行的流程中,如果线程A获取到锁进入创建对象实例,这个时候发生了指令重排序。当线程A 执行到 t3 时刻(singleton已经非null了,但是却没有初始化),此时线程 B 抢占了,由于此时singleton已经不为 Null,会直接返回 singleton对象,然后使用singleton对象,然而该对象还未初始化,就会报错。我们只需将 singleton 变量声明成 volatile 就可以禁止指令重排,避免这种现象发生。

参考/好文:

菜鸟教程 – 设计模式--https://www.runoob.com/design-pattern/singleton-pattern.html

掘金 --https://juejin.im/post/5d54c2d251882542f27bdff6

双重校验锁 --使用volatile和两次判空校验的更多相关文章

  1. Java基础教程:多线程杂谈——双重检查锁与Volatile

    Java基础教程:多线程杂谈——双重检查锁与Volatile 双重检查锁 有时候可能需要推迟一些高开销的对象初始化操作,并且只有在使用这些对象时才进行初始化.此时程序员可能会采用延迟初始化.但要正确实 ...

  2. 对象部分初始化:原理以及验证代码(双重检查锁与volatile相关)

    对象部分初始化:原理以及验证代码(双重检查锁与volatile相关) 对象部分初始化被称为 Partially initialized objects / Partially constructed ...

  3. 单例模式中用volatile和synchronized来满足双重检查锁机制

    背景:我们在实现单例模式的时候往往会忽略掉多线程的情况,就是写的代码在单线程的情况下是没问题的,但是一碰到多个线程的时候,由于代码没写好,就会引发很多问题,而且这些问题都是很隐蔽和很难排查的. 例子1 ...

  4. 关于Java单例模式中双重校验锁的实现目的及原理

    开始复习设计模式,一开始理解单例模式中的双重校验锁卡住了,想通了后就自己做了段思维导图来帮助自己理解. 其实理解下来并不难,但还是记录下来帮助自己回忆和借机试试养成写博客的习惯~ public cla ...

  5. 双重检验锁模式为什么要使用volatile?

    并发编程情况下有三个要点:操作的原子性.可见性.有序性. volatile保证了可见性和有序性,但是并不能保证原子性. 首先看一下DCL(双重检验锁)的实现: public class Singlet ...

  6. Java中单例七种写法(懒汉、恶汉、静态内部类、双重检验锁、枚举)

    /*** * 懒汉模式 1 * 可以延迟加载,但线程不安全. * @author admin * */ public class TestSinleton1 { private static Test ...

  7. Java中的双重检查锁(double checked locking)

    最初的代码 在最近的项目中,写出了这样的一段代码 private static SomeClass instance; public SomeClass getInstance() { if (nul ...

  8. 单例模式双重检验锁的判断是否为null的意义

    关于双重检验锁首先简单来看一个小例子: public class Singleton{ private static Singleton instance = null; private Single ...

  9. 双重检查锁实现单例(java)

    单例类在Java开发者中非常常用,但是它给初级开发者们造成了很多挑战.他们所面对的其中一个关键挑战是,怎样确保单例类的行为是单例?也就是说,无论任何原因,如何防止单例类有多个实例.在整个应用生命周期中 ...

随机推荐

  1. 云服务器AWD平台搭建

    开学后实验室来了几个新同学,在线上CTF方面大家一直在持续学习,但AWD模式的CTF我们练习并不多,所以准备搭建一个AWD平台用于实验室成员的线下赛攻防练习. 最开始的是防灾科技大学的线下AWD靶场: ...

  2. PHP代码审计分段讲解(1)

    PHP源码来自:https://github.com/bowu678/php_bugs 快乐的暑期学习生活+1 01 extract变量覆盖 <?php $flag='xxx'; extract ...

  3. [SUCTF 2019]Game

    buuoj杂项复现 下载了之后给了我们一张图片了网站的源代码 图片简单分析了之后没有什么内容,先看源代码的index.html 里面有base32编码,解码 ON2WG5DGPNUECSDBNBQV6 ...

  4. centos 7系统,解决python3.x 安装后使用yum不能安装的问题(错误:urlgrabber-ext-down | KeyboardInterrupt)

    1.在安装python3.xx版本后,通过yum去安装软件会出现问题,目前我遇到的有2种问题 比如显示:urlgrabber-ext-down Downloading packages: File & ...

  5. scrapy爬取微信小程序社区教程(crawlspider)

    爬取的目标网站是: http://www.wxapp-union.com/portal.php?mod=list&catid=2&page=1 目的是爬取每一个教程的标题,作者,时间和 ...

  6. 排序算法-Java实现快速排序算法

  7. Kubernetes Python Client 初体验之node操作

    今天讲一下k8s中对于各个实物节点node的操作. 首先是获取所有nodes信息: self.config.kube_config.load_kube_config(config_file=" ...

  8. 移动端H5微信分享

    移动端H5微信分享功能,可以使项目更好地传播. 微信官方教程文档:  微信JS-SDK说明文档 步骤一:绑定域名 先登录微信公众平台进入"公众号设置"的"功能设置&quo ...

  9. 前端js实现九宫格模式抽奖(多宫格抽奖)

    介绍: 前端九宫格是一种常见的抽奖方式,js实现如下,掌握其原理,不论多少宫格,都可以轻松应对.(代码可复制直接运行看效果). 该案例以四宫格入门,可扩展多宫格,奖品模块的布局可自由设置. <! ...

  10. STL——容器(Map & multimap)的简述与构造

    1. map/multimap 的简介 map 是标准的关联式容器,一个 map 里存储的元素是一个键值对序列,叫做 (key,value) 键值对.它提供基于 key 快速检索数据的能力. map ...