00:00
各位同学大家好,接下来我们将进入我们本章节最难的一章AQS源码的深度讲解和分析,那么这个呢,会带着大家呢,深度的解析AQS的源码,帮助大家彻底掌握guc底层的基础框架和它的核心设计思想。那么通过前面的知识储备,我相信大家对AQS啊是个什么,比如说as内部的类noe节点应该有个大体的认识,那么所以说我们现在打开我们原来的这张图,给大家说过,所谓AQS啊就是一个队列同步器,那么既然是抽象的,那么需要被继承,作为一个总的架构,它就解决两个问题。第一锁的使用,谁先抢到的状态标志为一,说明有人在占用。第二个锁的分配,抢得到的你去使用,抢不到的你给我规规矩矩进来排队,到时候你是要脱离队列取消,或者到时候被唤醒,该怎么个继续使用资源由AQS的统一给你在通知等待唤醒这些机器上给你做好了封装,那么接下来我们呢?
01:09
开工。按照如下章节给大家进行说明和讲解,先做一些约定,首先我们以洛可接口的实现类,那么为什么要与它呢?通过前面我们大家都清楚AQS啊,它是一个基础的底层框架,有这么多类都跟他有关。基于课时和时间精力的分配,我们不可能挨个挨个全讲,那么根据举一反三的原则,你通一个就会全部通,所以我们拿look。它作为突破口,也就是我们后面这儿所说的,以公平锁原车落口作为为例,作为突破口,那么从方lock方法开始解读,从所得占用到所得分配给大家彻底拿下,那么通了一个以后,我相信其他的大家也能够顺利的。走通打通关。所以在这儿。
02:00
提前给大家做好一些相关的约定和说明的讲解,好,那么接下来我们来吧。都清楚,Re lock底子就是aqs,这个我们在前面的源码都给大家介绍过,那么它呢,这个类它是实现了lock接口,那么对于洛克接口,它呢,基本上就是通过注意聚合了一个队列同步器的什么子类完成线程的反问控制,由它。那么聚合队列同步器搞定了锁的占用,那么谁现在洛克按洛克这段里面就说明某一个线程在使用着锁,那么其他那些抢不到的呢?那么通通去队列里面排队,那么通过这样的一种聚合功能完成了锁的分配和锁的使用。那么来吧,我们首先来看一下lock的原理,那么我们呢,将会从lock开始解读AQS的源码,先看一下架构图。来,首先lock接口,凡接口必然要有落地的实现,内re enter lock lock内部又有一个。
03:08
C口这么一个对象,同步G这个类,它又继承了aqs,那么我们对外面用户操作的基础API。叫洛克啊洛克,那么从我们的构造方法到我们的洛克API的使用,实质而言,底层就是操作心口这个类,由这个类又延伸出了我们的公平所和非公平所,OK,好,同学们。架构图理论先整明白,脑子里面有个印象,待会儿我就不再切换了,下面源码说话来。一定要注意。我们这个呢,用过的最经典的就这段代码,那么从构造方法开始,我们都晓得你给他写个force。或者。你根本什么都不写,默认这个就是一个非公平锁,但是如果你写个错,那么默认它就是公平锁。所以我们先从构造方法开始给大家进行讲解和说明,什么都不写,这个就是一个非公平锁,先看构造。
04:15
点开注意。跳到了re lock里面,好,那么re enter lock里面,他就告诉你这儿有个新号,那么告诉你这个构造方法,实际上而言是你有了一个什么非公平锁,OK,好,这是第一步,那第二步啊,我们可以看出它直接说的你构造了一个原车lock的实例,这个就等价于你使用传了一个什么force,也就是你什么都不写,或就就代表你也就传了个force,就是一个什么非公平锁,第二个。请看我这是错点,看大家请看什么都不传,或者写false是跳到这个方法,而如果你传了个false,它就让你判断这个值是不是个false还是处,那么这个时候如果是处,那么兄弟公平组如果是个false。
05:04
非公平所OK,所以说结合我们刚才那张架构图,我们就清楚lock一体两面,根据true和false它的情况传公平还是非公平好,那么同学们请大家看。假设。我们按照我们现在最常用的先来了解它的架构,我们这个是一个非公平锁,那么跑到这儿洛克,请大家看洛克是谁的,是这个接口的好,那么接口里面的方法要有此类来实现和落地,那么这个lock我们现在请看有这么多选哪一个,当然要选我们的re en lock。现在从lock接口跳转到它,然后我们会发现re enter的洛,其实底子跟刚才我们的架构图一模一样的说法,底子就是超重。Think这个对象好,又是C这个对象的落方法,我点开,大家请看,此时我们就获得非常清晰的认可,软的lock实现了。
06:03
Lock这个类实现了lock接口,而这个类里面又有包含着一个抽象的静态内部类think think考又继承了abstract。AQS,我们的抽象的队列同步器,这个里面。带有对外暴露的look方法再来,那么这个方法我们晓得现在我们传的是公平还是非公平,我们默认用的是非公平点开,所以说在这我们会看得出这个方法里面就是非公平方法的落地实现,它有if else2层判断,这层判断就是compare and sett,什么叫就是我们这儿的状态位零空弦一占用,如果第一个线程过来使用。抢占某个资源,我希望当然是空闲,没有人占用。如果说我抢到了OK,就把这个状态改成一,说明从零的空闲状态变成了一的使用状态,并且set exclusive owner thread就是设置独占的当前拥有的线程,那么就是当前线程它自己OK,那么好,这是一幅,否则的话和快尔方法OK,所以说这个就是我们洛克初步的一个概念,好,那么如法炮制,同学们刚才是非公平锁,那么如果我现在变成公平锁呢?
07:20
来。点开进来点开大家请看它是什么。公平锁继承SYNC。大家请看look方法,诶和刚才就不一样了,就没有那个if else判断,直接acquire占用,所以说acquire后面那么又是另外一对方法,我们后续再说。那么通过现在小试牛刀,我们可以进行一下初步的总结,图就是这张图,但是它底层的东西需要同学们认认真真的从洛克方法给大家看了一下,公平和非公平,那么好,我们下面回到我们的脑图。首先。
08:00
通过刚才的讲解我们会清楚,Re的lock这个类实现了洛接口,这个类里面有个静态类不类叫S,它继承了aqs啊,而他。在这个我作为基点,就在它又实现了非公平所和公平锁么底design就是这两个构造方法,那么大家呢,从理论回到我们的源码,大家呢,可以搂一眼,现在在我们的look我点开。这个是不是我们的。基础work这个类,这个类里面有很多方法,但这个。过往下面有三个CC是class静态累不累的意思,这有一个C没问题吧,那么在这个里面又有公平和非公平,所以说。我们大家呢,就会清楚原来的lock底子啊,其实说穿了就是操纵这个C口,这个继承了AQS的这个类。
09:01
对外暴露出非公平和公平所两个分支啊,OK,好,理论咱们对上,那么理论上大家看。如果我什么都不写,默认就是六了一个非公平锁,如果我传了布尔池to和false to就是公平,False也就是非公平,那么对于这样是创建的是公平,所对于这样创建的是非公平,对于这样创建是非公平,都用源码给大家详细的从理论到源码讲解过。所以我们在这。可以看出继续往下。那么在这儿,洛克我们一步步来假设现在我们可以看得出是。公平锁洛克。隔到这儿我们要找re enter lock里面的实线在这儿点开,在这儿在找,同学们请看我们现在是错是公平锁,公平锁这儿有个acquire么一个方法点开进去以后有一个try acquire这么一个方法点开,大家请看跳到哪了。
10:03
Abstract这个队列的同步器,哦,原来TRY块这个方法是负类所持有和定级的,还记不记得我们前面强调并说明一个前置知识叫什么呀?设计模式指什么?模板设计?这样的一种思想,那么大家请看,跳到了我们AQS最高级的副类,请看这儿,这个方法做了个定义,但是类类里面的实现是什么?抛出一个不支持的操作的异常,也即这就是我们的钩子。我负类定义了这样的一个方法,尝试抢占,去尝试抢占获得所我负类没有实现,因为AQS是所有guc多并发类的负类下放到子类,你们去实现,这儿就是我们的一个钩子,那么来请看有这么多人实现过,我们找谁啊?我们本次啊,我们找的是什么?恭喜,因为我们传了个错,点开大家请看,那走起,这个就是什么我们的线程来抢索的时候踹嘛,尝试是否能够占用强到那么这个当前线程这个C啥意思啊,就是得到这个AQS的状态标志为零,就是空闲大于一,那么这个就是什么我们的占用,那么来这些后续我们会想讲关键就这。
11:27
这个是原程洛里面的公平所得分之二,这儿有一个什么黑。Q的sister sisters,也就是说是否队列里面有前置的节点,那么就多这么一个,OK,好?那么接下来同学们,我们回到我们的脑图来看一眼,对于我们的公平锁,现在呢,全部搞下来了,那么对于我们的非公平锁呢,那么有兴趣的同学可以自己下去,按照我刚才的套路再翻查一遍他们两个的区别,就是否是有这个has qui persistence这么一个方法,其他没有任何区别,所以说公平他要先去,先来后到,看看我前面有没有排队,而非公平那就是先战先得,群雄逐鹿,所以说在这儿我们呢,回过头去。
12:19
以我们的公平为例,就多了这么一个方法,非公平的呢?没有?大家请看其他的代码,两边都一样,那么点开它。这段代码so easy就是判断前面有没有排队的线程,那么根据它的返回值是个布尔,如果是错,说明有一个正在排队的线程。在当前线程之前,如果返回false,说明当前这个线程就是这个队列的头,就是排第一个的,或者说当前这个队列就是一个空的队列,OK,所以说呢,他们两个没什么太大的区别在这儿TRY块这个方法公平和非公平就。
13:05
是否有这么一个,那么来,所以说公平锁和非公平锁log方法唯一的区别啊,因为底子他们都要是调用这个TRY宽啊,就是在获得所的时候是否多这个限制条件这个方法,那么这个方法是公平所。OK,在加锁时候判断等待队列中是否存在有效节点的方法,那么刚才也已经说过了,它是反馈一个布尔值,错就说明在我之前还有节点。如果是false,说明当前这个线程就是在这个队列里面的头节点,或者说这个队列是不是空的,就这么点好,那么所以说再从这我们呢,就可以看到。最简单的,我们从洛克方法就会明白,我们后续呢?我们呢,就以我们常见常用的非公平锁作为突破口,所以接下来我们继续再往前走一点,以它作为突破口,用look方法来给大家进行讲解和说明。
14:03
根据刚才我们已经明白了对比的公平锁和非公平锁的出快方法的实现代码,区别就在于非公平锁要比公平锁少一个判断就是是否前面有这个节点排队的。如果有这个就是判断是否需要排队,导致公平锁和非公频锁的差异有这么一点点小小的区别。一对于公平说,它讲究先来先到。排队打饭先占的先得,那么线程在获取锁的时候,这个锁的等待线,这个锁的等待队列中已经有线程在等待,那么当前线程就会进入到等待队列,哎,很公平,但是非公平锁呢,那就不好意思了,不管是否有等待队列如果可以获取锁,则立刻占有锁对象,也就是说队列的第一个排队线程塑形以后,假设我现在。杨哥在队列里面规规矩矩的排着队。如果按照公平说。
15:00
这个,那么返回错,我应该是第一个获得锁的排队嘛,但是如果是非公平锁,那么大家就是。吃相难看,不讲武德,我现在在队列里面,就算我排队排了很长时间,我苏醒了,理论上我应该首先获得锁,但是不好意思啊,不一定就是排头的这个线程获得锁。他还要需要参加所的竞争,那么也就是说有点类似于我在这排队呢,我是先到先得,但是队列以外的这些人,说不定他呢抢的比我还狠。可能我排队排了白排了,后来的线程不讲武德,注意差队罗锁了,哎,这个就是公平和非公平,那么前面我们也说过,公平锁雨露均沾,大家都有机会抢到这个锁多一些。而非公平锁效率优先,谁先把这个活干完,谁就拿到锁,所以说他不讲武德,OK,那么最终我们会发现。Re lock,它呢?Lock这个方法前面也刚才也见识过,如果对于我们这儿啊,不妨我们再来一次啊,假设这是非公平啊,因为。
16:09
洛卡。挂到这儿,我们现在是re enter的look搁到这儿。得到这儿我们现在请大家看,对于这个如果是非公平的话,那么大家请看,我们跑到这了以后,If else就是acquire,点进去acquire了以后就是try acquire听到所以说如果说是我们在这儿非公平,先走右边这个分支look,那么如果是非公平的话,那么来。不排队就是抢,抢得到直接占用,抢不到再去acquire OK,好,这只是非公平,那么下面我们呢?回到我们的公屏,那么搁到这儿了,以后同学们请看。刚才是非公平,现在是公平,公平就没有刚才那么疯抢那么一个状态,不讲武德的。这小这个if这个判断他直接过来,如果走的是公平这个分支啊,大家请看,很快啊,那么所以说我们可以通过圆码和我们的笔记获得这样的结论,创建完不管你是公平还是非非公平锁,你只要调用lock方法都会进行加锁,那么最终都会掉到AC块,这个方法好,那么大家请看这是我们的什么公平的这个状态,公平的话给我排队先来先得AC块,那么来这个是try AC,那么来搁到这弓形,大家看这个是不是要。
17:34
排队来看看前面有没有这个节点,To和forces以后才允许你干,有排队的你要先让人家走,没有排队的好,那么这个时候干嘛轮到你了再去干,所以说这个就是什么先占先得,但是这哥们就像我说的不讲武德,什么意思啊,他没有排队这个概念,他这有个if思,那抢如果能直接抢到,我直接上手去用了,抢不到到我再去排队,所以说通过这个源码的分析我们会清楚。
18:00
不管你怎么着,最终都是acquire方法,那么acquire方法里面就是我们本次讲的。源码分析的三段,第一个try acquire,第二个A加入到等待队列最后。加入到我们这个队列里面,这个这个这个三段方法的分析,那么这个就是我们后面要给大家进行的我们源码解读走起的三部曲,也就是我们这个。这个这个这三个方法的使用好,那么请大家坚持加油。
我来说两句