00:00
好,各位同学。根据前面所述。我们呢,如果不加这个S。我们在单机版下面的。案例模式是正确的,但是换到多线程版本以后是迅速出事了。好,第二步怎么解决呢?我们这儿加个星空袋子。可以解决了,但是我们讲过你你为了你你在这儿加个size干嘛。太重。那么在高并发的环境下面,你倒是数据一致性呢,但是并发性是不是下降了?也就是说,我们真真正正需要控制的就这么一行。那么接下来。我们来看一下。我们在。高并发下面怎么写?那么这个时候请看。我们要DC模式。那么这个DCM模式什么呢?Double。Check look俗称什么东东呢?
01:01
双端。检索。机制。好,也就说在进来。和。判断题进来和进来之后。分别判断两次有点类似于过了两次安检。那么同学们请看。这些东西都一样不动。第一个如果说注意我这没加S方法了啊,尽量不要用S方法,这是重锁,把整个方法都给锁了。如果这块为难,我进来干嘛?我们要同步。代码块。好,开始加锁。那么。干什么呢?再进行一次判断。
02:03
如果等于烂了。那么这个时候同学们请看。来是不是在加锁之前和加锁之后都进行。一次判断,这么说,同学们能理解。什么概念呢?比方说我现在要去上卫生间。卫生间没人了,我确认没人了,我才走过去,然后进去了。把门刷插上。然后正常情况下。我该干嘛干嘛,然后呢,我不放心,塞上门栓以后再推推这个门,确实推不动了,我才干活。这么说能跟上。好,那么同学们言下之意就是所谓的双端检索机制,就是在加锁的前和后我都进行了一次判断,那么这样的话,坦白讲没有把SYNCH加到这,我们只是需要同步代码段这一块加了SYNCH,而且进行了前后两次判断,那么这样的话是不是更加的牢固一些?
03:05
那么好,同学们,那你写完了以后能不能运行成功呢?大家看,现在没有多条构造方法了吧?那么大家看这块没有多条构造方法了吧?好,那么这块。是不是我们的。DCL版的。大力模式。就写完了呢。反正都叫单子或者单立哈,无所谓,反正两个一个意思。非常抱歉的通知大家。没有。杨哥,不对啊。你这儿运行三遍。貌似确确实实控制了,我们讲过,甭废话,你只要单利模式一定会调到这个构造方法,只要调用这个构造方法,就要打出来这么一行,目前你这十个线程来PK,是不是永远只打出来一行啊?那为什么这个东西还不对呢?
04:01
我告诉你,这种情况下,运行十次可能都正确,100次、1000万都正确,但有可能你的正确性只是99.99%。因为。上一讲我们说过。在多线程环境下面。他为了。性能和效果。一层有指令重排。如果。你现在没有控制好指令重排,就会出现这种现在所写的单立模式。下面。会。出异常的情况可能这种机会是什么?运行1000万次才会出现一次。那么这个时候什么情况呢?下面双端检索机制,我们呢。干嘛?先写到这儿。重点不是写这个单利模式啊,重点是学我们的valentine。从头写到尾,同学们有没有发现我现在这个代码里面,我根本就没有在任何地方加过?
05:05
没错吧,那杨哥你不是讲bad吗?在哪呢?这这个现在这个代码里面哪有bad。接下来加好加,但为什么要加,你加在哪呢?要先跟同学们阐述清楚。接下来请跟我走。这块知识就非常的烦。我们单立模式的DC的代码。老师刚才已经全部写了。为什么这个单利模式还会有一个潜在的隐患呢?请跟着我来。那么这个时候同学们请看这儿。我遮着一点。双端检索机制啊,不一定现场安全啊,你崩溃了,那老师那你还给我讲啊。因为有指令重排序的存在。我们只能加入volatile,才能让上一个程序写的更加完美。什么意思呢?
06:01
请看。我们刚才的某一个线程执行到第一次检查读取到ince不为难的时候。这个是第一种根本就没有不为难,第二种是对象可能没有完成初始化的工作,第一种是根本就没有,第二种是有了,但是呢,他还没有完成初始化,听懂了吗?就比方说抬头同学们现在一排一座这个位置第一种。老师的名单上面根本就没有这个人,这个永远是那听懂了吧,但是现在呢?我说同学们和大家说一下,这个位置现在被占用了。一个小时以后,有个叫张三的插班生,他要坐这个位置回答我,那么这块内存空间,这个位置是不是已经被分配出去了?理论上他不为空了,但是目前这个人还没有到叫初始化,还没有完成,听懂了吗?有名无实。那么此时。
07:00
下面请看。我们来判断以后是不是instance the new。这一步。会被分成为三部。首先。我内存AOC底层源码。要分配对象的内存空间,为什么?因为你溜出来的东西,我是不是要分配个空间。刚才那个差班生张三要来我们班学习,回答我,我是不是要给他配个座位,这个座位就是一个内存空间,这一步同学们能跟上。第二个初始化对象。好,什么叫初始化对象呢?比方说我为这个空桌子配好一根网线,弄好一个插座,等着这个新同学插班入座,听懂了吗?第三步,它来了,Instance实例指向这个内存空间设置指向了刚刚分内存空间,此时instance不等于烂了什么概念,抬头三步。同学们。一排一桌,这个位置待会来个新的插班生,叫张三同学回答我,我这块内存空间是不是已经分配出去了?
08:05
能跟上好我们刚才的原话什么,一个小时以后他过来。那么这种情况下正常的顺序,我们在这儿给他准备好网线桌椅。还有。插电电源板。一个小时以后请看。这一块第二步就是初始化,为这个同学准备插线,网线能跟上一个小时以后。这哥们来了,张三来了,那么我们的instance。那么同学们的instance就是各种各种眼睛就看到,哦,原来一个小时以后到的这个张三的这个插班生是长这种样子。这一步能跟上。那么到这儿都挺顺利吧?先申请空间,同学们,这个位置你们不要用了,有新同学报到,他要做这个位置,一个小时以后到,那么这一个小时以内,我们是不是要完成初始化工作,比方说给他插线板,桌子擦干净,给他配根网线,一个小时以后真人到这个位置了,同学们,我们看到张三长什么样,没问题吧?
09:04
这个是正常情况,但是抱歉。语句一、语句二、语句三不存在数据依赖关系。而且,无论重排前还是重排后,程序的执行结果在单线程中并没有改变。因此这种重排指定重排怎么着?是允许的。那么这个会导致一个什么问题呢?正常情况下,语句123。那么重排以后,可能某一次编译器给他重排了它的底层执行顺序。却变成了132。那么言下之际。同学们。现在一排一座。会有一个叫张三的同学。插班过来坐这个位置,现在兄弟们,我们是不是要给他分配这个内存空间,分配一个桌子。
10:05
你们也知道,一排一座,张三这个同学要做了。正常情况下干嘛?他入住我们一个小时以后。他才到这一个小时,我们就先给他准备,来了以后他坐下来了,同学们的引用你们的目光,你们的眼睛才看到这块真人现场名副其实啊,一排一座,这个位置有谁了?这个张三长什么样?这种是正常情况,同学们听懂了吗?但是由于指令重排。过来查。Some。有可能底层被优化以后跑到二的前面,因为三和二不存在数据依赖关系,请看。Instance等于memory。干嘛设置instance?就是同学们的目光指向了刚刚分配的这个内存地址,就是现在的一排一座这个座位,此时张三这个人还没来呢。对象还没有完成初始化。可能张三还在教务处办这个插班手续,体验报告呢,他还没到,但是你们的instance,你们的引用,你们的目光已经先看到这儿了,听懂了吗?
11:09
那么这个时候,虽然说老师嘴巴上说同学们这个座位上是要来一个新的同学叫张三,但是此时有名无实,听懂了吧?你看这个座位你来取,现在来这个座位上,你们的目光看到这个座位来取值有这个位置。有这个内存地址,有这个桌子,但是上面没有真人坐着听懂,那么这个时候请看。你们那instance在这儿。干嘛初始化对象,也就是说对象还没有初始化完成的时候,你们就看过来了。此时张三这个同学还没有落座,你们看到的这个位置是有人被占了,但这个人还没有到,这个叫有名无实啊,听懂。上一种顺序执行,这个叫名副其实啊。申请座位一个小时以后,张三到,一个小时以后,你们再去看,刚好这个位置就有张三这个人,你们的引用你们的目光看到了这个座位上面坐着一个真人张三,这个时候不等于难听懂。但是由于。
12:12
二三倍对调。将会导致他还没有初始完成的时候,由于是多线程。某些线程抢的比较快,他直接过来这取值的,由于刚才老师才说这个位置啊,一排一座,我们将会分配一个叫张三的同学来入座。那么这个时候导致什么?某些同学的目光,就是某些现成的引用已经一判断,干嘛呢?他不为空了,我过来取。但是由于还没有完成初始化,导致有名无实,我取到了这个地址上的值是个空。那么呢,因为指令重排导致我出现某一次渠道空值的情况,那么好。这个时候理论上说完了以后,同学们我们再往下看。
13:02
指令重排只会保证创新予以执行的一致性,就是单线程,下面下面你就是指令重排了,没事儿,昨天我们是不是说过单线程无所谓,但现在。多线程间的语义一致性就会存在。潜在的风险。所以当一条线程访问的instance不为空的时候,但是又刚好由于instance的实力。未必已经初始化完成。也就说还没有完成初始化,我去取值啊。那么这个时候就造成了现场安全。那么来,同学们,我们回到我们的代码,再跟同学们说一下。正常情况下。好,班主任来说各位同学。一排一座,这个位置有没有人?同学说没有。那么好。班主任说。一个小时以后,我们将会来一个插班生张三。那么这个时候回答我这个位置是不是被班主任锁定了?
14:00
同不同意那么好。接下来。确实这个位置啊。张三还没有入座,那么没有人再确认一次班主任?班主任将会给这个位置的实力分配的一个实力对象张三。现在这个位置坐一排一座,这个地址啊,内存地址,这个位置坐的人就是张三兄弟们能跟上。好。这种情况就是我们什么脑图板的上面这个123。先翻配内存。地址就是座位,然后等待着张三入座。张三入座了以后,同学们的目光才看向张三,此时是什么名副其实?这个。引用地址啊,做的人就是张三,你怎么取都不会错。但是抱歉。由于存在指令重排。
15:00
有可能过来了以后。干嘛?我们在这儿确实分配给张三了,但是张三还没有入座。同学们一句判断。Instance。等于烂吗?不等于啦,因为老师说了,这个座位已经分配给张三同学了,你去拿。但是抱歉,由于张三还没有入座,这个内存地址啊,这个座位是分配出去了,他这个真人还没有坐过来。那么这时候你你跟我讲,我这个CE1取,是不是有可能得到什么地址,是不为空,但是这个地址的实际。内容是空,这个座位老师班主任通知了,要分配出去给张三这个同学,但是张三这个真人还没有坐到这儿,这个时候将会导致空,听懂了吗?那么也就是说,这种指令重排是我们不希望的。那么同学们,我们这个东东怎么禁止指令重排?二话不说。所以说需要在这儿加完了太。
16:01
告诉大家。不要指定重排。下面这种情况。用V控制啊。保证在多线程间的语域一致性。如果你不加由于指令重排某一次。将会出现县城不安全问题。我要保证大家同学们一排一坐这个位置啊,有一个插班生将会过来。那么这个座位,这个内存地址是不是被分配了?他不为空了,名字意义上已经分给张三了。然后。初始化等待着张三下来,张三坐实了,有人了,同学们才能够看到这个地址对应的这个真人长什么样,这个时候干嘛?Instance啊,张三不等于烂了,同学们去使用才能加他的微信,要他的手机号,这个时候干嘛?张三这个人才叫名副其实,坐在了这个内存地址,坐在这个座位上,同学们去取才不为空,多线程环境下面才能保证线程安全。
17:04
能跟上。听不听得懂?OK,那么好,那么兄弟们,这个就是我们vlaile是吗?单例模式的相关分析,也即如果在高并发多线程的版本里面,那么我们的单立模式最终的写法,第一个双端检索机制二。在我们需要单立的这个对象前面加外径止指令重排。听懂,一定要等它加载完了以后我们才去取,不要那么自作聪明,还没有加载完,还没有初始化完成,你先去取。好比现在你跑到空位置,跑这个位位置这儿找张三,人还没到呢,你去访问,那么这个时候是不是自己去吃闭门羹啊?好,那么这个就是兄弟们需要了解的单利模式的DC加V版本的。招聘发环境下的解法,好,那么这一讲我们就给大家介绍到这儿。
我来说两句