其他分享
首页 > 其他分享> > DCL锁双重检查;

DCL锁双重检查;

作者:互联网

学习来源于: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中可以分为以下几条指令完成:其中每一步都有可能被其他线程抢断

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

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

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

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

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

锁定的代码只能保证:

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


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

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

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



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