00:00
我的原子性问题。这是啥意思啊,你你听我讲。同学们,你们想想看,现在呢,这个是个零,我拿过来改成一,把一写回成零的过程是这样的判断,如果你哥们你是不是依然为零,对吧?如果你确实依然是零,那么我这时候把你的这个零给你变成一,不就这个过程吗?那现在假设我就问你,如果在你判断完依然为零还没有改的时候,另外一个线程把它改成八了,你那时候咋办?所以这个肯定不行。如果想完成CAS操作,必须保证CAS的操作是原子性。好,这两大类两大问题不知道说清楚没有,有一个我解答过了,另外一个我还没有解答。我一会儿解答给你。到底是怎么保证呢?
01:00
好,可以继续同学了,扣一来。你们还还还还在听吗?还能跟上吗?嗯。OK,看这里。VO,行了,明天讲吧,为什么?你们对VO有这么多的执念呢?你觉得他能完成所有的事是吗?别扯我了,能干的事很少。好,大家看这里。那么它到底是怎么来保证的呢?回过头来看我们的源码。嗯。刚才啊,我们跟跟跟跟着CS代码跟跟跟跟完之后跟了一会儿发现它是native了。这是unsafe这个类,这个类unsafe。这个类里面一个native的代码能不能看,完全可以。如果你要看的话。打开C加加代码看,这就是C加加代码。
02:04
有同学说,老师您别这样,讲完go讲Java,讲完Java讲C,加加。在哪在哪跟得上啊。大哥,你想挣七八十万上百万,跟着我的思想思路走就行,而且真的没有你想象中的那么难,因为难题全被我解决了,你跟着走就行。黑色看不清没关系啊,像老师这么体贴的男人。你放心。像老师这么体贴的男人。嗯。肯定是都跟你写在了笔记里了是吧?就是说我在笔记里给你详细的记录,如果你想跟进来,跟到C加加代码的时候去哪里跟。很简单,去哪里跟呢?哎,去哪个。
03:02
类里面哪个方法里面。哪个方法里面,哪个类里面直接去跟就可以啊。好,笔记会提供吗?当然会了,明天吧,明天我修改里面,修改一点里面的内容啊,可以可以没问题啊。Tomorrow。这个C加加代码怎么打开,这个稍微有点复杂,你得需要下载open jdk源码,然后搭建测试环境,然后把代码给打开,我是直接给你打开的。好,大家看这里。我们继续继续来聊,我们刚才聊过啊,说在那个呃,Java的代码里面,我们已经读到什么地方了呢?就是当我们调用CAS的时候,实际上呃,它调用的是unsafe这个类的compare and swap in,对吧,还记得吗?当然,如果你要找CR代码,实际上是在这里,注意看,它也是unsafe的CP嘛。然后。
04:00
找对应代码,在这找叫compare and swap。笔记我已经给你详细记录了它是在哪行,所以你要想读的话,跟着我笔记走就可以。我们来跟踪一下这个CAS到底它是怎么实现。最终比较的原子性的。这块还能跟上吗?能跟上,给老师扣一来。大概啊,就是C加加你可能不懂,但是你跟个大概就可以。好,大家看这里。当我们得到这个方法的时候,Compare and swap。其实你往下读,你会发现它调用的是atom这个类的compare and方法,看到了吧?Compared and。好,那我们就跟进去呗,看看这哥们儿里边。Go to DeFinition。这代分式比较多,我就直接定位到最终的这块就行了。好,最终就在这儿。在这个。
05:01
呃,头文件里面就托克X86的实现。就是原子的这个类,在Linux上X86这种架构上的一个实现,到底是怎么实现的呢?在这儿。米这个类的compare and exchange方法。呃,我这个字体能放大吗?我看一眼。放在了哪里?啊。给大家放大一点啊。嗯。这是哪个方法?好,我们来看这个方法。下面我们来看这个方法。在这个方法里面,它到底是怎么实现的?它是一个汇编的实现,Asm叫assembler。OK,汇编,汇编语言实现,这个汇编代码里面呢,是这两条指令来实现,叫lock if MP以及exchange。
06:11
好了,同学们,这个过程呢,我就不直接给你这么一点点详细的演示了,你呢。看我们这个笔记。呃。在这个笔记里面。跟踪来跟踪去。最终的一条实线就在这儿,叫lock if MP,然后后面呢,是跟一条指令叫compare and exchange,我先说结论,听我说。先说结论。呃,跟不上了吗?还能跟上吗?跟不上,要不然今天就。
07:03
懵了是吧?呃呃呃,OKOK,我慢慢稍微回顾一下啊,我们稍微回顾一下,大家记得吗?我上来先讲了现成的概念,然后讲了锁的概念,锁的话呢,是一个synchronized,对吧?呃,但是呢,为了提高效率,除了synchronized之外呢,它提供了guc的包,在这个doc的包里面呢,使用的是CA的方式来上锁,CAS方式来上锁的意思它它就是我们来刚才分析过CS的概念,就是比较并交换。然后呢,面试题里头呢,有第二道就是比较并交换的时候,你要保证原子性,它是怎么保证的。怎么保证原子性,我现在已经讲到这儿了,嗯。嗯。好。是不是稍微稍微就是懵懵一点的同学,是不是稍微可以继续了。
08:00
不用死机,不用死机啊好,大家看这里啊,马上就要攻打山头了,我们现在就是最核心的是我要保证CAS的原子星吧,对不对。CS原子性怎么保证的呢?注意看,最终的实际上就在于就在于一条汇编语言上,这条汇编语言叫做lock。呃,当然呢,呃,中间呢,有一个叫lock ifp,我稍微解释一下,这个lock ifp呢。有人听我讲MP的意思叫做呃。呃,Presence。不对。好像有问题。叫么?呃。Ors processor OK?叫做。多核。多个盒好吧。
09:02
好,看这里啊,多处理器啊,我是故意的,我是故意的,我看看大家有没有在认真听讲啊。好,叫做多核,多核处理器前面加lock。单核处理器只需要一条指令。所以我们先得出第一个结论,所谓的CAS在最底层是由谁来支撑的呢?是由这条指令来支撑的这条汇编指令,这条汇编指令叫做compare and exchange,所以我们说这么来理解,就是一个CPU去访问内存的时候,完全可以有一种方式,这个方式就是CAS方式,就是这条指令来完成。你这里有零,把我这CPU过来改成一,我马上就给你写回去比较一下,好,这个就叫做compare and exchange。但是。在多核的时候前面必须加lock。原因是什么,你们。考虑一下原因是什么呢?我们来画个图。
10:02
这是这颗CPU,这是另外一颗CPU。通过一条总线去访问内存里的某个值,第一个CPU把这零拿过来的时候。注意用compare and exchange指令改成一,把一往回写的时候,发现你依然是零,我就可以把这个零给你,给你变成一了。但是问题就在于,这条指令是不能保证原子性的。原子性不能保证,就会发生什么情况呢?最后把零拿回来改成一,判断一下你依然为零,这个过程有可能另外一个CPU已经把这零给改掉了。这是不行的。那为了让它保证原子性怎么办?就干这么一件事,叫lock,请大家记住这条指令。所几乎所有CPU都支持的一条汇编指令,这条指令叫lock。Lock的意思叫做锁总线。
11:03
左总线是什么概念?就是我这颗CPU在执行后面这条指令的时候。Compare an exchange。把总线锁住。只让我来用,别人不能用。好了,这就是在汇编语言上的一个实现。OK。好,看这里我再说一遍。在这里面有一个误区,有同学说,老师,我单核CPU就不用加lock了吗?大哥加lock的原因主要就是说执行后面这条指令的时候,不被其他CPU打断,对吧,保证原子性嘛。那我就想问你一句,你自己在执行一条指令的时候,都能把自己给打断吗?
12:01
自己先把自己打死,再去打,再去打敌人是吗?先把自己杀了,再去杀人。不可能。所以只有在多核CPU的时候,当然现在都是多核,所以最终的CAS的实现就是这条指令,叫lock compare。呃,我们稍微回顾一下,我估计讲到从讲到讲到现在呢,有小伙伴们有可能有一些些些些些许的晕菜是吧,晕菜呢也很正常,我先跟你说一下,因为这里呢是真是少说50万年薪左右的内容,所以有点晕才是正常的。呃,不着急,听我慢慢给你捋,我呢最开始给大家讲的呢,就是现成的一个最基本的概念。以及呢,线程用户空间的线程和那个内核线程的一个对应模型JVM是1 : 1。
13:00
Go long呢,是M比N这么一个关系。多线程访问的时候需要了解锁的概念来来保证数据的一致性。锁。最最早开始的时候,像Java的这个锁,最早开始的时候要经过操作系统的老大来帮我调度,这个叫重量级锁。后来Java进行了优化,诞生了GUC这个包,这个包里面有各种各样的工具,比方说lock,比方说。Atomic,好,这些东西它背后的原理是什么?它背后的原理不是重量级,它是在用户空间解决的,这个叫做轻量级锁,也叫做自选锁,它的实现方式是什么呢?它的实现方式是CAS。CAS的概念我给大家讲了。零写回来比较依然为零,给你改成一,但是比较的过程会产生两个问题,第一个是ABA问题,可以加班班号来解决。第二个是。必须保证比较并交换这条指令的原子性。怎么保障的呢?最终我们根根根你就会发现是用这条指令来保障的。好,讲到这里的时候,任何面试官在问你关于这方面的问题。
14:12
你就可以吊起来揍他了。GS里面都是CAS实现的,对,这UC里面全都是CAS实现。嗯。好了。呃。我们那个。可以继续吗?我讲到现在为止。问,啥是c compare exchange cns比较并交换呀?刚才我不说了吗?嗯。你为了50万年薪,是不是也该拼一拼,对不对?嗯。嗯。
15:05
讲到现在为止呢,我基本上讲清楚了,就是。CAS是啥意思,轻量级锁对吧,重量级锁又是啥意思?重量级所嗯。但是现在我还没有给大家讲所谓的锁的四种状态,就是synchronized的。实现原理听我听我说。新版的synchronized,它比较牛逼。它并不是像原来那样直接使用重量级锁。在synchronized的执行过程之中。它实际上经历了一个所升级的过程。看这里。我们先说结论,还是那句话啊,学东西呢,先学脉络。实际上呢,现在的synchronized他经历了一个偏向所,偏向所。偏向左。到轻量级锁,也就是CAS,也就是自选锁。
16:04
到重量级锁的一个升级过程,今天还来不来得及给大家讲升级过程啊。嗯。嗯。也许我来一杯水了。嗯,我知道你们有各种各样的问题,主要我给你省略了很多细节,这个没招。第八大奇迹你都问了好几遍了,读一读?那个那个那个那个那个源码一看就明白,很简单的啊。嗯。
17:01
为什么喝水让我们看着?因为我要有有段时间不说话,你以为我去世了吗?我让你看着,表示我还活着好吧。嗯,这个过程呢,相对来说也比较复杂啊,讲完的话估计俩小时。呃,我呢,先跟大家讲一点初步的内容好吧。听听。这里面有几个概念啊,第一个概念呢,叫做。偏向,所第二概念呢叫轻量级锁,第三个念叫重量级锁,我先解释这三个概念,其实有两个概念我已经解释完了,轻量级锁。重量级锁下面还有一个所呢,叫偏向所,偏向所是面试的重灾区,这是面试的重灾区。这里面的细节超级多,呃,但是呢,我我基本上也都给大家写在了文档里啊,你只要是。愿意朝着更高的薪水去努力,稍微花点时间就把它拿下并不难。
18:03
你只要听我讲就不难。OK。我可以开始了吗?今天讲的内容。不难吧?是不是很多概念也就明确了,嗯。聊一聊啊,今天聊最后一个内容偏向所。然后给大家演示一点小程序,好吧。请开始你的表演,我就不表演。初学者能听懂,对,我是争取让初学者都能听懂啊,你认真听就能听得懂,至少听你大概,嗯,好,西瓜超人已经饿了,我们先来聊偏向所这个概念。所谓的偏向所是什么概念呢?偏向锁不是一种锁。它不是锁,严格来讲它不是锁,不是说要插进钥匙,就把这把锁给锁定了之后,好,下面的执行的时间片就归我了,只有我一个线程在这里面可以运行,不是这么回事儿。
19:06
偏向左的意思是。这把锁非常非常的轻,比那个轻量级还轻,他严格来讲不是一把锁。它所谓的占有这个坑的,别的都是都是上锁对吧,他不是。它是什么呢?就直接把名贴在门上就可以。比方说。雨,我看见了雨了是吧?哎,雨说这是我第一个人,他作为第一个县城想进来占有这个坑,想拉个便便。雨呢,就直接把自己的名字往上一贴,啪叽往上一贴,OK,搞定好了,这个坑归我了。好了,这就是偏向锁。有同学说,老师,这太简单了吧,那跟那个别人要抢那把锁有什么关系呢?认真听我讲,这把偏向锁最关键在于不用抢。
20:06
只要你第一个线程过来,这把锁就是你的,就偏向于第一个线程。所以偏向所最关键的是不用抢,你懂吗?只要把这个ID号,把你现成的本人的名字往上一贴就可以。有同学可能就会讲了,说老师具体到底是怎么实现的,贴在哪呢?我一会儿用代码演示给你看,你就理解了,好吧,我先给你讲概念。偏向所就是把自己名字往上一贴。不用跟其他人去抢,锁好了,这把锁归你了。那有同学可能就会说了,说老师,如果你这个名字贴在门牌上的时候,有另外一个哥们儿过来了。欢乐马。来了,说你这个雨啊,怎么在里边老不出来,我来了,你凭什么还继续再往里边怎么办?第二个奋斗也来了,田坤也来了,对吧?这哥仨都来了。
21:04
说不行,这个不能老偏向于,偏向于你一个人。我也要抢这把锁,怎么办,升级?怎么收?把你的名字给扯下来,擦,撕下来。然后大家伙开始抢,怎么抢?转圈CAS方式,自旋的方式,拎着裤子转圈,谁抢到就算谁的,谁把自己的名字贴上去,谁持有这把锁好了就算谁的,这个叫第一次锁升级。第一次所升级就是从偏向锁,然后直接升级到了轻量级锁,自选锁。但有同学听到这儿呢,可能会有疑问啊,说老师这事不对呀。这个为什么要有这么一个偏向所,那我上来之后大家自选抢不就完了吗?为什么第一个线程还要偏向他一下呢。
22:03
是不是?大家会会有这个疑问吧,有这个疑问的给老师扣一。听我讲。这里面的内容稍微深一点啊,你认真听。呃,大家知道啊。呃,有一些那个。比如说vector。比如说hash。啊,比如说那个像还有什么。那个那个那个那个那个那个string。八。这些类大家应该都听说过吧?好,这些类里面的方法有一特点。这些方法都写了。Synchronized。里面有一方法。
23:01
方法全写了synchronized。好,那我就想问你啊。我们先假设。根据呃,整个的工业界的一个调查。虽然说这些方法全上了锁了。但是在百分之七八十的情况下,实际执行的时候只有一个线程在运行,它们你们可以自己回想一下,有的时候你们自己就调用了里边这个方法,但是真的会有多线程在抢吗?百分之七八十的时间只有一个线程在这里运行。好了。那这个时候你就想了,如果百分之七八十的时间只有一个线程在这儿运行的话。当我需要synchronize的时候,我我我我我所竞争的时候。我总是要竞争一下的话,这个效率就太低了。我能不能这个线程来的时候,我不让他有所竞争,直接往上贴一个ID号就可以,你直接把自己ID贴到这就可以。
24:06
把自己名字往上一贴,这样就省了很大时间的一个所竞争过程。省的竞争过程,效率是不是就提升了?我们再说一下。假如不存在这这把平行锁,那么我是不是看到synchronized的,我就得。动用竞争机制啊。即便是你只有一个线程,我也要你参与整个竞争机制,你得上去做个演讲竞选。是你这把锁财归你。所竞争GVM内部一个管理锁的过程,你可以想象一堆代码得来得帮忙让你管理整个锁的这个过程,假如没有偏向锁这个事儿的话,你这个代码必须得启用。让即便你只有一个线程,你也得经历这个代码的流程之后才能拿到这把锁。
25:01
所以偏向锁,严格来讲不是一把锁,就是第一个线程来了,我就假设没有竞争,假设都是你运行在百分之七八十的时间,你就你只要直接往上一贴就是你了。不知道这个大概的意思,我说清楚没有?还有没有同学有疑问的?懂了是吧,嗯。好了,这就是偏向锁。那有同学说了啊,当然。呃,这里面呢,其实。嗯,有一些特别复杂的面试题啊,我们稍微过过过一点点,看看大家能不能接受。一贴不稳定,废话,当然不稳定了。你贴上你名字,什么时候所升级啊?只要有人过来抢,就得进行锁升级。听懂了吗?我再说一遍。只要有你把你名字贴到这儿了。只要有一个人过来抢这个锁,就必须得升级。
26:03
因为这个时候就有竞争了,听懂了吗?就俩这哥俩得抢了,谁抢到算谁的了。OK。好了。所以偏向锁呢?就是为了优化那些百分之七八十事件只有一个线程在运行synchronized的代码所设计的一把锁。我觉得最基本的概念大家应该了解了,是吧,嗯。好。那下面的问题呢?我们就来看一眼这个偏向所能。嗯。鹏鹏,第一个县城来的时候怎么知道不需要竞争?大哥,如果你是GVM你就知道。你要是JVM你就知道听懂了吗?GVM代码里面自己判断呀。对,一个线程是偏向左,两个线程自选组yes。
27:03
嗯。无所,大家记住,无所这个词儿最好别用。就这个词儿,是特别恶心的词儿。无所这个词你们最好别用。非常容易产生歧义。概念这玩意儿啊,是大家发明出来,用来方便交流的。以前原始人的时候,不知道这个东西是什么,只能说这这这这个这个这个这个说不清楚,后来大家发明这个概念,说这叫便便,好,以后一说便便知道什么意思。有人发明了这个词,叫无所,这个词太讨厌了。这个词无所原来的意思叫做没有重量级锁。所以所谓的自选,所谓的CS,它都叫五锁。但是呢,后来又又又有人把这个叫程自选锁,那他那无锁到底是不是,到底是不是把锁别抬这杠,理解什么意思就行。你不要跟孔乙己似的,跟那儿纠结回的有多少种写法,没意思。
28:04
好吧。我们可以继续了吗?可以继续给老师扣一哇,十点了。领会精神就行,对啊,就是没有重量激素,原来这个意思啊,好。再看这里。我们来看依然回回到这张图啊。我靠,我都觉得讲的有点多了。你们,你们还能撑得住吗?嗯。完全没问题是吧,嗯。给老师来宣传课程了,行,一会给你宣传啊。很有意思,对。打开这里啊,锁的四种状态是哪四种呢?拗出来刚刚扭出来,没有锁的状态。偏向锁状态、轻量级锁状态、中量级锁状态,这就是锁的四种状态。中间有一个各种各样的升级的过程。
29:02
呃,作为偏向所来说,什么时候升级成轻量级锁呢?其实非常的简单,你你好好想想就知道了,就是只要有一个人过来跟你抢,就得把你这哥们撕下来,不是把你撕下来。撕下来之后咱俩开始抢对吧,这时候就就就升级成轻量级所了,轻量级所就是大家拎着裤子转圈在那等,你就想象形象一点知道吗?你己拎着裤子转圈转,转来转去的跟那等着说哎,轮不轮到我了,轮轮到我了,OK,这个就叫氢量激素。重量级所示。拎着裤子的人太多了,实在是那个CPU忙不过来了,怎么办?扔到队列里去。那现在问题就在于,什么时候轻量级会生成重量级呢?这个呢,细节其实比较好玩,需要我讲吗?基本上就是判断你旋转多少次,比方说你拎着裤子转了十圈都没轮到你,不好意思进队列。等待的人太多了,我CPU最多能接待20个人,你现在都来了40个人了,不好意思进队列。
30:05
就这么简单。一说就明白。
我来说两句