ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

DCL锁双重检查;

2022-02-07 18:02:41  阅读:233  来源: 互联网

标签:DCL 加锁 检查 代码 双重 指令 线程 单例 new


学习来源于:B站马士兵视频:《计算机底层原理

DCL:Double check lock。

其本质是为了解决多线程中语句执行不确定性

你也不知道当前其他线程进行到哪里,哪里都有可能。

比如在单例模式中,需要判断单例对象是否已经存在,if如果单例存在:则返回单例。否则else就去new一个单例。

这样做有一个问题:当涉及到多线程时,可能有多个线程同时来判断单例是否存在,此时,有两个甚至多个线程同时判断为不存在,则多个线程都会去创建单例。这样还是很多对象。

如何避免,首先考虑加锁,即判断单例是否存在的这个操作,应该加到锁中,判断加锁这个操作,本身也要加锁。

即我们:

S1:先判断单例是否存在,(第一次check

S2:如果不存在,那我们就要加锁,准备执行创建对象这个过程。

S3:加锁完成后。注意:此时有可能有多个线程,同时判断check发现单例不存在,那么这个锁一旦解开,其他线程还是会进入锁区重新创建对象,所以,需要在锁区,进行第二次check判断单例对象是否存在。这个在锁定代码区中先进性的二次判断单例是否存在,就叫做:DCL。

S4:在锁区内部,第二次check之后,判断单例是否已经存在,如果存在,那么就直接返回,否则创建。

总结:

就是Check-Lock-Check


此时可能有新的疑问:第一次检查不要可以吗?

不可以:为了避免不必要的锁。假设有一万线程,然后有一个线程抢到了,那么锁释放后,后面其他9999个线程要挨个锁一遍,然后检查单例对象是否存在,然后再出锁。这个一进一检查再一出,是不必要的麻烦。

有了外面这个锁,那么一旦有一个线程new了之后,其他9999个线程,就不用再费劲了。



这样DCL之后就结束了吗?

还没有,CPU执行代码语句逐条指令执行的。

我们看起来是一条语句,但是在CPU中却是很多条指令

这个单单的一条语句: new obj = new object();

这条语句在CPU中可以分为以下几条指令完成:其中每一步都有可能被其他线程抢断

  •  第一条new:在内存中开辟空间。
    • 这个空间的大小取决于T,里面的内容在一开始初始化的时候,不同的语言(C/C++、Java/C#)等,处理方式不同。
    • 马老师说Java会给相应类型的默认值。重新赋值:就像分配了一片新的土地。这个土地初始里面种了什么东西,不用的语言处理方式不同。Java会像耕地一遍,重新犁一遍。
    • 所以Java的初始化会比C/C++要稍微慢一点。因为多了一个重新赋类型默认值的过程,这样也稍微安全了一点。有利有弊。
  • 第二条:dup,马老师未讲。
  • 第三条:一开始是变量默认值为0。默认值是new时候的值,代码中初始化为8,初始化在第三步执行。特殊调用T的init初始化方法,就是默认的构造方法。
  • 第四条:变量t是一个指针,要通过t能访问到这块堆空间。所以要把这个对象的地址赋值给t。
  • 第五条:完成。

以上概括起来:三板斧:一个小小的对象初始化就要:有三步来实现:

  1. 首先分配空间:new(),然后赋予成员属性默认值。(类型的default值。)
  2. 调用构造方法:T.<init>,然后赋予成员属性初始值。(构造函数中指定或者传入的值。)
  3. 建立关联:指针变量t指向对象所在的内存空间。 

这里涉及另外一个问题:不仅仅程序执行的时候顺序不确定指令执行时,也有指令重排的问题。

 上锁的代码和不上锁的代码能不能形成并发?能。

所以新的一个线程可以基于目前thread1的线程进度访问到成员属性的状态。即:当指令执行到重排的第二条:7 astore_1时,此时锁中的线程实现了对m = 0的赋值。外界线程可以读到当前单例半实例化状态。

锁定的代码只能保证:

  • 1、原子性。
  • 2、可见性。
  • 保证原子性更新完之后才可以对另外一段上锁代码可见最终状态。
    • 唯一不能保证的就是线程的有序性。
    • 所以锁的代码内部依然可能发生换顺序。

基于上面来看:好像什么代码的执行顺序都可以改变的样子?什么样的顺序不可以换?

  • 判断能不能换,主要一个原则:只要保障 单线程内 数据最终一致性
    • 比如:a = 0;b = 0;这两条指令哪个先执行,数据最终都一致,所以这两条指令顺序可以发生重排。
    • 再比如:x = 0;x = 5;这两条指令:不可以交换顺序。因为数据最终不一致了。
  • 上面指令,最终结果都是成员属性m = 8;所以顺序不影响结果。可以交换。

只要保障了线程最终数据一致性就可以交换顺序。

程序优化有两个级别:编译器级别的优化;CPU级别的优化。

无知者无畏:达可效应——丁宁克鲁格效应:越是啥都不会的,胆子越大。马老师希望大家走出自己的愚昧之谷,走上求知之路。



标签:DCL,加锁,检查,代码,双重,指令,线程,单例,new
来源: https://blog.csdn.net/xiaoyaolangwj/article/details/122810464

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有