Double-Lock Checking

DCL锁双重检查; 学习来源于:B站马士兵视频:《计算机底层原理》 DCL:Double check lock。 其本质是为了解决多线程中语句执行不确定性。 你也不知道当前其他线程进行到哪里,哪里都有可能。 比如在单例模式中,需要判断单例对象是否已经存在,if如果单例存在:则返回单例。否则else就去new一个单例。 这样做有一个问题:当涉及到多线程时,可能有多个线程同时来判断单例是否存在,此时,有两个甚至多个线程同时判断为不存在,则多个线程都会去创建单例。这样还是很多对象。 如何避免,首先考虑加锁,即判断单例 阅读详情

Double-Lock Checking,也就是所谓的“双锁检测”,是实现Java并发安全的一个重要手段。比如单例模式的双检锁,先看下面代码:

class Foo { 
    private Helper helper = null;
    public Helper getHelper() {
    if (helper == null) 
         helper = new Helper();
         return helper;
    }
   // other functions and members...
}

这个在多线程状态下可能会生成多个Helper()实体,故不能正常工作。修改如下:

class Foo { 
  private Helper helper = null;
  public synchronized Helper getHelper() {
    if (helper == null) 
        helper = new Helper();
    return helper;
    }
  // other functions and members...
}

这个虽然可以正常工作,但是效率太低,因为我们的目的仅仅是在初始化第一个Helper对象的时候需要加锁,其他时候根本不用。因此就有了第三种方法:

class Foo { 
  private Helper helper = null;
  public Helper getHelper() {
    if (helper == null) 
      synchronized(this) {
        if (helper == null) 
          helper = new Helper();
      }    
    return helper;
    }
  // other functions and members...
}
上面代码看似解决了效率问题,但是在很多编译平台下还是不能正常工作,关键在于helper=new Helper()这里。helper=表示给新的实体分配内存,然后再调用Helper()的构造函数来初始化helper成员变量。那么线程A和B在调用getHelper方法,A先进入,刚分配完内存,还没来得及调用构造函数就被踢出了CPU,然后B再进入,发现helper!=null,开始调用return helper,但是返回的却是一个没有初始化的对象(当然基础类型比如int就没有这个问题,因为不是类,不存在调用构造函数这一步)。可以用volatile关键字来解决(Java 5以后适用),也可以将helper声明为一个独立类的一个成员变量,即

class HelperSingleton {
static Helper helper= new Helper();
}

因为java的Lazy initiazation(即使用时才初始化)特性,而这个会在类加载时就初始化。而采用volatile关键字解决的代码如下:

class Foo {
    private volatile Helper helper;
    public Helper getHelper() {
        Helper result = helper;
        if (result == null) {
            synchronized(this) {
                result = helper;
                if (result == null) {
                    helper = result = new Helper();
                }
            }
        }
        return result;
    }

    // other functions and members...
}

这段代码加入result的含义是在helper已经初始化的情况下,保证对volatile helper变量只访问一次,因为返回的是result而不是helper,所以能获得25%的性能提升。


双锁检测还有一个应用的地方是在cocurrentHashmap里的putIfAbsent方法里,该方法的实现如下:

    default V putIfAbsent(K key, V value) {
        V v = get(key);
        if (v == null) {
            v = put(key, value);
        }

        return v;
    }

一目了然,如果对应的K没有V,就将V放进map去。所以应用的时候一定要小心。很多人不理解这个函数,将V设置为一个new Object(),导致每次都要初始化,比如这样:
map.putIfAbsent(name, new HashSet<X>());

其实本意是如果name有对应的HashSet就不初始化了,但很遗憾putIfAbsent函数的实现告诉我们这是不可能的,那么如何解决呢?可以用如下的双锁检测代码:

Set<X> set = map.get(name);
if (set == null) {
    final Set<X> value = new HashSet<X>();
    set = map.putIfAbsent(name, value);
    if (set == null) {
        set = value;
    }
}

这里一定要注意第二个if(set==null),千万不能丢。具体原理如何我也不太懂,以后再研究。当然JDK 1.8里提供了一个新的computeIfAbsent()函数,可以很好的实现线程安全,替代了putIfAbsent()这个让无数程序员跳坑的坑爹函数,实现如下:

Set<X> set = map.computeIfAbsent(name, n -> new HashSet<>());
computeIfAbsent函数内部的实现原理这里不再详述,因为我现在也没看太懂.....





Java中双重检查锁(double checked locking) 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。双重检查锁(Double-Check Locking),顾名思义,通过两次检查,并基于加锁机制,实现某个功能。// 此处如果有多个执行流同时进入,会造成多次初始化// 第1次,一般性检查,但是有并发隐患:可能有多执行流同时进入改处// 此处第2次检查,为了防止后续多执行流并发时,后续获取同步锁的执行流,不会再次初始化Singleton对象。 阅读详情

相关推荐

基于AQS驱动的ReentrantLock公平锁和非公平锁实现原理解析

本文通过代码调试分析了ReentrantLock的可重入特性及其底层AQS实现机制。重点解析了: 通过state变量记录锁重入次数,加锁时CAS递增,解锁时递减; 以NonfairSync为例展示了非公平锁的直接抢锁逻辑; 揭示了AQS通过volatile state变量和CAS操作实现同步状态管理; 完整跟踪了lock()/unlock()方法的执行流程,说明AQS是JUC锁工具的底层基础。

pysense的博客 863

Java 中的Double Check Lock(转)

对于多线程编程来说,同步问题是我们需要考虑的最多的问题,同步的锁什么时候加,加在哪里都需要考虑,当然在不影响功能的情况下,同步越少越好,锁加的越迟越优是我们都必须认同的。DCL(Double Check Lock)就是为了达到这个目的。 DCL简单来说就是check-lock-check-act,先检查再锁,锁之后再检查一次,最后才执行操作。这样做的目的是尽可能的推迟锁的时间。网上普遍举的一...

iteye_5555的博客 427

【ERROR】ERROR1: PROJ: proj_create_from_database: Cannot find proj.db - 环境变量配置与路径修复指南

本文详细解析了地理空间数据处理中常见的【ERROR】ERROR1: PROJ: proj_create_from_database: Cannot find proj.db 错误。该错误的根源是PROJ库无法定位其核心数据文件proj.db。文章提供了从问题诊断到修复的完整指南,包括如何在不同系统(Windows/macOS/Linux)和安装方式(Conda/pip/源码编译)下找到正确的proj.db文件路径,并通过设置PROJ_LIB环境变量(临时、代码内或永久)彻底解决问题,同时给出了进阶排查技巧和

m2n3o4p5的博客 557

双重检查锁(double-checked locking)

在软件工程中,双重检查锁(double-checked locking[1])是一种设计模式,通过在加锁前检查锁标志(criterion),可以减少加锁的开销。只有当标志显示需要的时候才...

felix021的专栏 4342

知识图谱本体建模工具Protege使用教程

1.下载 先去官网下载:protégé 直接下最新版,点击会有注册页面,只填必填项的name和project description即可。 下载后解压即可使用。 2、安装可视化工具Graphviz 去官网:Download | Graphviz下载。下一个最新版的zip就行。 我解压在了Protege文件夹下,然后在 Preference下指定目录。 指定一下你解压完的Graphviz下的dot.exe,确定。 PS:如果这样报错就尝试在环境变量的系统变量的...

子麒的博客 2万+

保姆级教程:用MS建完分子模型,如何一键转成LAMMPS能用的data文件?

本文详细介绍了如何将Materials Studio(MS)构建的分子模型转换为LAMMPS可用的data文件的全流程。重点讲解了力场选择、环境配置、转换命令参数解析及常见问题排查,帮助初学者快速掌握MS与LAMMPS之间的数据转换技巧,特别适合计算材料学领域的研究人员。

weixin_42665255的博客 471

单例模式

懒汉式 在使用的时候才去检查有没有实例,有就返回,没有就初始化一个。 存在线程安全问题,使用双端检索机制解决。 class Single{ private Single(){} private static Single single = null; public static Single getInstance(){ if(single == null){ single = new Single(); } reutrn single; } } 饿汉式 一开始就初始化好实例对象,好处是线程安全,坏处是浪

NuanShuTT的博客 524

PPPoE上网配置不求人:华为路由器命令行操作指南(2023最新版)

本文提供2023年最新的华为路由器PPPoE上网配置命令行操作指南。通过详细的步骤讲解,从连接设备、创建拨号接口、绑定PPPoE客户端到配置内网与NAT,手把手教你完成配置,并附有验证排错方法,助你轻松实现稳定上网。

s4t5u6v的博客 679

java volatile关键字内存原理

内存屏障(Memory Barrier) 1.可见性 写屏障(Sfence)保证该屏障之前的,对共享变量改动都同步到主内存中去 读屏障(Ifence)保证该屏障之后的,对共享变量读取加载的为主内存中最新数据 2.有序性 写屏障在指令重排序时,不会将写屏障之前的代码排到屏障之后 读屏障在指令重排序时,不会将读屏障之后的代码排到屏障之前 volatile原理 volatile底层原理基于内存屏障 对volatile变量写指令会在之后加入写屏障 对volatile变量读指令会在之前加入读屏障 如何保

qq_24693491的博客 415

AI应用架构师实战:半导体器件仿真AI智能体系统搭建

半导体器件仿真(如MOSFET、FinFET等)是芯片设计的核心环节,传统流程依赖专家手动调参、多物理场仿真引擎(如TCAD)耗时(小时级至天级)、经验难以沉淀,导致研发周期长、成本高。如何构建一个AI智能体系统,实现仿真任务的自动化调度、参数智能优化、结果分析与知识沉淀,成为提升半导体研发效率的关键挑战。

移动开发前沿的博客 1222

中科大大数据学院2023年保研夏令营机试题目【无offer,直接放题了~】(2023.07.22下午14:35-17:35考试)

给定一串数字,最后一个数是0表示结尾,表示数字串的终止,为无效数字。将该数字串存储在双向链表中,判断是否为回文串,若是,则输出Yes,否则输出No.

m0_51339444的博客 1921

设计模式-单例模式(JAVA实现)

单例模式: 确保一个应用程序某个类只有一个实例,并且自行实例化并向整个系统提供实例单例实例。 单例模式特点: 单例类只能有一个实例 单例类必须自己创建自己的唯一实例 单例类必须有可以给其他对象提供这一实例的方法 Java实现单例模式可以通过两种形式实现 饿汉模式(类加载时就完成初始化,所以类加载较慢,但获取对象的速度快 这里是线程安全的 //饿汉模式的singleton 类加载慢,...

ZHWVICDI的博客 248

Python 爬虫实战:全国高校录取分数线数据爬取与院校对比分析

本文介绍了一个基于Python的高考志愿填报辅助系统,通过爬取掌上高考平台的全国高校录取分数线数据,构建本地数据库并实现智能分析。系统主要功能包括:1)使用requests+BeautifulSoup爬取院校基本信息和历年分省分科类录取线;2)通过SQLite实现数据持久化与增量更新;3)利用pyecharts生成分数线趋势图、院校对比雷达图等可视化图表;4)提供"冲稳保"三档智能选校推荐。技术栈涵盖网络爬虫、数据清洗、数据库管理和可视化分析,可为考生提供数据驱动的志愿填报决策支持。项目采用模块化设计,包含

u014481728的博客 238

多线程下的单例模式:双检锁,以及volatile的使用(HB规则)

参考几位高人的文章,然后结合自己的理解,在此做一个小小的总结: http://www.iteye.com/topic/537563 http://www.iteye.com/topic/260515 http://www.iteye.com/topic/344876 在多线程环境下的单例模式: [b]1. 使用(Double-Checking-Lock)双检锁:[/b] [code...

ayagen的博客 232

【论文解读--Xdog】新型电驱式四足机器人研制与测试

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录系列文章目录前言一、四足机器人体型大小和驱动方式的比较二、四足机器人设计一些重要的结论三、系统控制框架四、系统硬件框架五、力位混合控制(阻抗控制)六、侧向平衡控制(和VMC如出一辙)七、电机驱动系统研制(FOC磁场定向控制)总结 前言 认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长! 本文先对新型电驱式四足机器人研制与测试做个简单的介绍,具体内容后续再更,其他模块可以参

qq_35635374的博客 3725

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

线程安全的单例模式

1. 单例模式这里有单例模式的wiki定义: In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is

toseektruth的博客 287

VB摄像头监控

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

Java 中的Double Check Lock

对于多线程编程来说,同步问题是我们需要考虑的最多的问题,同步的锁什么时候加,加在哪里都需要考虑,当然在不影响功能的情况下,同步越少越好,锁加的越迟越优是我们都必须认同的。DCL(Double Check Lock)就是为了达到这个目的。  DCL简单来说就是check-lock-check-act,先检查再锁,锁之后再检查一次,最后才执行操作。这样做的目的是尽可能的推迟锁的时间。网上普遍举的

zbl_zbl的专栏 1188

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

java中的双重锁定检查(Double Check Lock)

  原文:http://www.infoq.com/cn/articles/double-checked-locking-with-delay-initialization#theCommentsSection 有很多知识点可以再延伸、消化一下。   双重锁定检查(Double Check Lock)这个词看上去有些摸不着头脑。但是如果你有兴趣看一下java框架的话,你可能会遇到这种代码(...

weixin_33788244的博客 368

Java中的双重检查锁机制模式(double checked locking)

2021年的金三银四一眨眼就到了,对于很多人来说是跳槽的好机会,大厂面试远没有我们想的那么困难,摆好心态,做好准备,你也可以的。另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。BAT面试经验实战系列:Spring全家桶+Redis等其他相关的电子书:源码+调优其他相关的电子书:源码+调优。

VIP129370的博客 1333

Singleton设计模式的C++实现详解

SingletonThe Singleton Pattern: ensures a class has only one instance, and provides a global point of access to it.只有一个实例的类,如下是若干考虑: 首先,要产生类实例,需要调用构造函数。为了防止用户申明或者new一个类的实例,我们可以把这个类的构造函数设置为protected

smstong的成长轨迹 2420

C++从入门到精通:现代C++开发环境搭建与核心语法实战指南

C++作为一种静态类型、编译式的通用编程语言,以其接近硬件的操作能力和对过程化、面向对象及泛型编程的支持,成为系统软件、游戏引擎和高性能服务器等领域的核心技术。其核心原理在于通过指针、内存直接管理等机制实现精细的资源控制,同时借助类、模板等高级抽象构建复杂系统。现代C++(C++11及以后版本)通过引入智能指针、RAII(资源获取即初始化)等特性,显著提升了代码的安全性和可维护性,其技术价值体现在对性能、实时性和资源占用的极致优化上。在应用场景方面,C++广泛应用于操作系统、数据库、游戏开发、金融交易系统和

weixin_34198453的博客 307

python3 核心笔记

本文主要是针对python3的一些核心要点做一些记录,感兴趣的可以关注和订阅。会持续更新,这个玩意学习一下,可以为数据分析和AI打下一定的基础。

yanghuashuiyue的专栏 617

你不得不知道的sync.Map源码分析

sync.Map源码分析 背景 众所周知,go普通的map是不支持并发的,换而言之,不是线程(goroutine)安全的。博主是从golang 1.4开始使用的,那时候map的并发读是没有支持,但是并发写会出现脏数据。golang 1.6之后,并发地读写会直接panic: fatal error: concurrent map read ...

weixin_34203832的博客 182

Caffeine Deep Dive

Caffeine: A High-Performance Java Cache Caffeine is a modern Java in-process cache library featuring: W-TinyLFU eviction: Combines LRU and LFU with a window (1% capacity) for burst traffic and adaptive sizing (0.2%-80%) Lock-free concurrency: Uses MPSC buf

quwenqian的专栏 524

Java Thread Pools — Deep Dive

Java线程池核心原理摘要 线程池作用:解决线程创建开销大、资源耗尽问题,通过复用固定线程、控制并发量、任务队列解耦任务提交与执行。Java提供Executor框架(Java 5+)实现。 核心类层次: Executor → ExecutorService → ThreadPoolExecutor(核心)/ScheduledThreadPoolExecutor(定时) ForkJoinPool:工作窃取,支持并行流和CompletableFuture ThreadPoolExecutor关键参数: core

quwenqian的专栏 389

深入解析TMS320F2838x Flash与ECC寄存器:嵌入式系统数据可靠性的底层保障

在嵌入式系统开发中,微控制器(MCU)的Flash存储器是程序代码和关键数据的核心载体。其数据完整性直接关系到系统的稳定运行,尤其是在工业自动化、汽车电子等对可靠性要求极高的领域。Flash作为一种非易失性存储器,其物理特性决定了它可能因环境干扰或器件老化而发生比特位翻转,即单粒子翻转(SEU)等软错误。为了应对这一问题,现代高性能MCU普遍集成了ECC(错误检查与纠正)机制。ECC通过在写入时生成校验码、读取时进行校验和纠错,能够自动检测并纠正单比特错误,检测双比特错误,从而从硬件层面为数据提供保护。这项

weixin_34185320的博客 394
上一篇: Java8 Stream类学习笔记
下一篇: 1002:487-3249(电话号码转换)
wengeyiming
博客等级 码龄14年 0粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值