首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Java单例模式中双重检查问题

在努力创建更有效代码时,Java 程序员们创建了双重检查锁定习语,将其和单例创建模式一起使用,从而限制同步代码量。...然而,由于一些不太常见 Java 内存模型细节原因,并不能保证这个双重检查锁定习语有效。 它偶尔会失败,而不是总失败。此外,它失败原因并不明显,还包含 Java 内存模型一些隐秘细节。...这就是“双重检查锁定”名称由来。将双重检查锁定习语应用到清单 3 结果就是清单 4 。 清单 4....双重检查锁定问题是:并不能保证它会在单处理器或多处理器计算机上顺利运行。 双重检查锁定失败问题并不归咎于 JVM 中实现 bug,而是归咎于 Java 平台内存模型。...针对 Java 技术 IBM SDK 1.3 版和 Sun JDK 1.3 都生成这样代码。然而,这并不意味着应该在这些实例中使用双重检查锁定。该习语失败还有一些其他原因。

1.9K20
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    双重检查锁定与单例

    双重检查单例 下面是我们经常使用一种单例实现,也就是双重检查实现方案。...首先当一个线程发出请求后,会先检查instance是否为null,如果不是则直接返回其内容,这样避免了进入synchronized块所需要花费资源。...其次,如果两个线程同时进入了第一个if判断,那么他们也必须按照顺序执行 synchronized 块中代码,第一个进入代码块线程会创建一个新 Singleton 实例,而后续线程则因为无法通过if...但还有一个问题,在有些情况下,通过这种方式拿到Singleton对象,可能是错误 。...回顾我们new对象3个步骤 1,分配内存空间 2,初始化对象 3,将对象指向刚分配内存空间 但jvm在指令优化时,会出现步骤2和3对调情况,比如线程1在经过俩层为 null 判断后,进入

    99930

    java双重检查锁单例真的线程安全吗?

    相信大多数同学在面试当中都遇到过手写单例模式题目,那么如何写一个完美的单例是面试者需要深究问题,因为一个严谨单例模式说不定就直接决定了面试结果,今天我们就要来讲讲看似线程安全双重检查锁单例模式中可能会出现指令重排问题...---- 双重检查锁单例模式 乍一看下面单例模式没啥问题,还加了同步锁保证线程安全,从表面上看确实看不出啥问题,当在同一时间多个线程同时执行该单例时就会出现JVM指令重排问题,从而可能导致某一个线程获取...指向刚分配内存地址 instance = memory; 看到上面指令重排解释之后,那么我们来回顾一下未加volatile修饰符单例为何会出现问题。...解决问题关键就在于volatile关键字,我们来看下volatile关键字特性。...、lock作用代码块自然是有序执行,volatile关键字有效禁止了指令重排序,实现了程序执行有序性; 看完volatile关键字特性之后我们应该就明白了,是volatile关键字禁止了指令重排序从而解决了指令重排问题

    3.5K20

    双重检查锁定及单例模式

    问题是,稍后经过证明,一些习语并不完全如其所声称那样,或者仅仅是与描述功能不符。在 Java 编程语言中,双重检查锁定就是这样一个绝不应该使用习语。...在本文中,Peter Haggar 介绍了双重检查锁定习语渊源,开发它原因和它失效原因。 编辑注:本文在针对 Java 5.0 修订前参考了 Java 内存模型;关于内存排序描述也许不再正确。...在努力创建更有效代码时,Java 程序员们创建了双重检查锁定习语,将其和单例创建模式一起使用,从而限制同步代码量。...然而,由于一些不太常见 Java 内存模型细节原因,并不能保证这个双重检查锁定习语有效。它偶尔会失败,而不是总失败。此外,它失败原因并不明显,还包含 Java 内存模型一些隐秘细节。...双重检查锁定问题是:并不能保证它会在单处理器或多处理器计算机上顺利运行。 双重检查锁定失败问题并不归咎于 JVM 中实现 bug,而是归咎于 Java 平台内存模型。

    1.8K30

    服务端性能优化之双重检查

    简介 早前文章中讨论过服务端性能优化之异步查询转同步,在本文中,将讨论双重检查锁定设计模式。通过简单地事先检查锁定条件,该模式减少了锁定获取次数,通常可以提高性能。...下面是之前关于锁和线程安全文章一些文章: Java服务端两个常见并发错误 操作原子性与线程安全 快看,i++真的不安全 原子操作组合与线程安全 单例锁Demo 首先,让我们看一个具有严格同步简单单例...实际上,Java内存模型允许发布仅仅部分初始化对象,而这又可能导致其他BUG。...替代方案 即使经过双重检查锁定可能会加快速度,但它至少存在两个问题: 由于它要求volatile关键字才能正常工作,因此它与Java 1.4及更低版本不兼容 它很冗长,使代码难以阅读 由于这些原因,让我们研究没有这些缺陷其他方案...在本文时,这被认为是编写单例最简洁,最安全方法: public enum EnumSingleton { INSTANCE; // 其他方法 } 总结 总而言之,这篇文章介绍了双重检查锁定模式

    86310

    双重检查锁为什么要使用volatile字段?

    双重由来 单例模式中,有一个DCL(双重锁)实现方式。在Java程序中,有时候可能需要推迟一些高开销对象初始化操作,并且只有在使用这些对象时才开始初始化。...后来,提出了一个“聪明”技巧:双重检查锁定(Double-Checked Locking)。想通过双重检查锁定来降低同步开销。下面是使用双重检查锁定来实现延迟初始化实例代码。...} } return instance; } } 双重检查锁定看起来似乎很完美,但这是一个错误优化!...问题根源 前面的双重检查锁定实例代码第4处(instance = new Instance();)创建了一个对象。这一行代码可以分解为如下3行伪代码。...解决方案一:基于volatile解决方案 /** * 安全双重检查锁定 * * @author xiaoshu */ public class SafeDoubleCheckedLocking

    1.3K10

    java:基于volatile和Thread Local Storage双重检查锁定实现延迟初始化

    下面这段很简单基于双重检查锁定(Double-checked locking)实现延迟初始化(Lazy initialization)代码,还是让spotbugs找出了问题(感谢spotbugs)。...原因很简单,这种模式在java下无效,因为filedNames 变量不是线程可见,具体原因涉及到java内存模型,网上已经有文章很深入介绍,参见本文末尾参考资料4 private List...双重检查锁定实现{@link ILazyInitVariable}抽象类 * 要求 JDK5 以上版本 * @author guyadong * * @param variable...package gu.simplemq; /** * 基于Thread Local Storage双重检查锁定实现{@link ILazyInitVariable}抽象类 * @author...》 《双重检查锁定失败可能性——参照《The “Double-Checked Locking is Broken” Declaration》》 《Java中Volatile关键字详解》

    89270

    单例模式-双重检查锁(DCL)和volatile 应用

    单例模式-双重检查锁(DCL, 即 double-checked locking) 代码示例如下: package com.hsy.demo; /** * 懒汉单例 * * 优点:懒加载,线程安全...10:04:33 * @since */ public static LazySingletonDCL getLazySingleton() { // 第⼀重检查是否为...} } } return lazySingleton; } } 解释说明 优点:懒加载,线程安全,效率较⾼ 缺点:实现较复杂 这⾥双重检查是指两次...⾮空判断,锁指的是 synchronized 加锁,为什么要进⾏双重判断,其实很简单,第⼀重判断,如果实例已经存在,那么就不再需要进⾏同步操作,⽽是直接返回这个实例,如果没有创建,才会进⼊同步块,同步块...简单说明⼀下,双重检查锁中使⽤ volatile 两个重要特性:可⻅性、禁⽌指令重排序。 这⾥为什么要使⽤ volatile ?

    77330

    java:基于volatile和Thread Local Storage双重检查锁定实现延迟初始化

    下面这段很简单基于双重检查锁定(Double-checked locking)实现延迟初始化(Lazy initialization)代码,还是让spotbugs找出了问题(感谢spotbugs)。...原因很简单,这种模式在java下无效,因为filedNames 变量不是线程可见,具体原因涉及到java内存模型,网上已经有文章很深入介绍,参见本文末尾参考资料4 private List * 要求 JDK5 以上版本 * @author guyadong * * @param variable...package gu.simplemq; /** * 基于Thread Local Storage双重检查锁定实现{@link ILazyInitVariable}抽象类 * @author...》][4] [《双重检查锁定失败可能性——参照《The “Double-Checked Locking is Broken” Declaration》》][5] [《Java中Volatile关键字详解

    43210

    速读原著-双重检查锁定与延迟初始化

    双重检查锁定与延迟初始化 在Java 程序中,有时候可能需要推迟一些高开销对象初始化操作,并且只有在使用这些对象时才进行初始化。此时程序员可能会采用延迟初始化。...因此, 人们想出了一个“聪明”技巧:双重检查锁定(double-checked locking)。人们想通过双重检查锁定来降低同步开销。下面是使用双重检查锁定来实现延迟初始化示例代码: ?...基于volatile 双重检查锁定解决方案 对于前面的基于双重检查锁定来实现延迟初始化方案(指 DoubleCheckedLocking 示例代码), 我们只需要做一点小修改(把 instance...通过对比基于 volatile 双重检查锁定方案和基于类初始化方案,我们会发现基于类初始化方案实现代码更简洁。...但基于 volatile 双重检查锁定方案有一个额外优势:除了可以对静态字段实现延迟初始化外,还可以对实例字段实现延迟初始化。

    62910

    双重检查锁,原来是这样演变来,你了解吗

    在看Nacos源代码时,发现多处都使用了“双重检查锁”机制,算是非常好实践案例。这篇文章就着案例来分析一下双重检查使用以及优势所在,目的就是让你代码格调更加高一个层次。...同时,基于单例模式,讲解一下双重检查演变过程。...上述过程,在锁定前和锁定之后,做了两次判断,因此称作”双重检查锁“。使用锁目的就是避免创建多个ConcurrentHashSet。...Nacos中实例稍微复杂一下,下面以单例模式中双重检查演变过程。...再回顾一下本文重点: 阅读Nacos源码,发现双重检查使用; 未加锁单例模式使用,会创建多个对象; 方法上加锁,导致性能下降; 代码内局部加锁,双重判断,既满足线程安全,又满足性能需求; 单例模式特例

    52120

    java安全编码指南之:锁双重检测

    简介 双重检测锁定模式是一种设计模式,我们通过首次检测锁定条件而不是实际获得锁从而减少获取锁开销。 双重检查锁定模式用法通常用于实现执行延迟初始化单例工厂模式。...延迟初始化推迟了成员字段或成员字段引用对象构造,直到实际需要才真正创建。 但是我们需要非常小心使用双重检测模式,以避免发送错误。...在多线程环境中,因为重排序影响,我们可能到意向不到结果。...那么上代码有没有问题呢? 有,bookDLC虽然是一个static变量,但是因为CPU缓存原因,我们并不能够保证当前线程被赋值之后bookDLC,立马对其他线程可见。...ThreadLocal版本 我们知道ThreadLocal就是Thread本地变量,它实际上是对Thread中成员变量ThreadLocal.ThreadLocalMap封装。

    48031

    单例模式双重检查锁模式为什么必须加 volatile?

    单例模式双重检查锁模式为什么必须加 volatile?...学习设计模式时候,知道单例模式是一种很常见设计模型,其目的就是为了避免创建过多对象,给jvm造成比较大压力,之前也对单例模型进行了比较详细描述,详情参考我之前博客:链接 如果要实现一种线程安全单例模型...,一般都会采用双重检查锁模式 public class Singleton { private static volatile Singleton instance; public...Singleton(); } } } return instance; } } 这里,就会有疑问,为什么要双重检查...对象是null,所以会进行new Singleton,这种情况,如果不加第二个if判断,第一个线程创建对象之后,之后线程会继续创建,所以这种就没做到单例 双重检查原因知道之后,为什么要加volatile

    1.2K30

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

    ,实现了程序执行有序性; 双重检查锁定模式 双重检查锁定(Double check locked)模式经常会出现在一些框架源码中,目的是为了延迟初始化变量。...下面来看一个 Spring 中双重检查锁定例子。...虽然之前了解了双重检查锁定模式原理,但是却忽略变量使用了 volatile。 下面我们就来看下这背后原因。 错误延迟初始化例子 想到延迟初始化一个变量,最简单例子就是取出变量进行判断。...第二次检查还未通过,才会真正初始化变量。 这个方法检查判定两次,并使用锁,所以形象称为双重检查锁定模式。 这个方案缩小锁范围,减少锁开销,看起来很完美。然而这个方案有一些问题却很容易被忽略。...上面错误双重检查锁定示例代码中,如果线程 1 获取到锁进入创建对象实例,这个时候发生了指令重排序。

    2.1K00

    并发学习笔记11-双重检查锁定与延迟初始化

    该并发学习系列以阅读《Java并发编程艺术》一书笔记为蓝本,汇集一些阅读过程中找到解惑资料而成。这是一个边看边写系列,有兴趣也可以先自行购买此书学习。...本文首发:windCoder.com 关于双重检测锁定,了解过单例应该不陌生,但也容易写错。这里以单例模式为例一起探索。...为了继续优化,因此人们想出了一个“聪明”技巧,即双重检查锁定(Double-Checked Locking,简称DCL): public class Singleton {...根据Java语言规范,在首次发生下列任意一种情况时,一个类或接口类型T将被立即初始化: 1.T是一个类,而且一个T类型实例被创建。 2.T是一个类,且T中声明一个静态方法被调用。...Java语言规定,对于每个类或者接口C,都有一个唯一初始化锁LC与之对应。 从C到LC映射,由JVM具体实现去自由实现。

    91820

    Java单例---双重锁校验详解

    双重锁校验单例 什么是单例模式?...单例保证一个对象JVM中只能有一个实例 直接上代码吧: /** * 双重锁校验单例 */ public class DoubleLock implements Serializable{...public static volatile DoubleLock doubleLock = null;//volatile防止指令重排序,内存可见(缓存中变化及时刷到主存,并且其他内存失效,必须从主存获取...变量 //注意上面这三步,第2步和第3步顺序是随机,这是计算机指令重排序问题 //假设有两个线程,其中一个线程执行下面这行代码...,大家自己看哈 上面代码埋了一个坑,就是这个类实现类implements Serializable接口,这就会使这个类在序列化时候单例被破坏,这个问题解决方式和原理请看我另一篇博客:java序列化破坏单例模式原理解析

    26450

    面试官:双重检查单例(DCL)要不要加volatile?详解来了

    大家好,我是mbb 单例对象在日常开发过程中,几乎是最常见设计模式之一了; 那在众多单例实现方式中呢,双重检查单例(Double Check Lock)又是比较常用一种实现方案,简称DCL; 具体实现代码如下...今天我们要探讨问题重点,并不是要不要加问题;而是为什么要加?...对象创建过程 我们先搞一个简单测试对象T,通过这个对象T来搞清楚对象创建过程。...,平均也都是在100多万次时候,出现问题,说明这个问题出现概率极低;我想如果不是BAT这样一线互联网大厂并发量,应该很难遇到这样问题吧!...(Invalidate)其Cache,这个操作相当于对Cache中变量做了一次Java内存模型中“store”和“write”操作。

    79640
    领券