系列 6:P31:Java中的锁是如何实现的? - 马士兵学堂 - BV1RY4y1Q7DL
呃今天呢主要来跟大家讲这个锁的东西,关于所这件事呢,通过一个小的实例来讲,我们就不讲那些个乱七八糟的理论性的东西了,一个小小的案例,这小案例呢喜闻乐见啊,大家肯定是学过或者至少自己敲过。
或者至少了解过叫什么呢,假如我们有一个值n,它最开始的初始值是零,然后呢我们启动了100个线程,这里有100个线程,每一个线程里面呢把这个值给它加1万次o,每次每一个加1万次啊。
那么最终的结果100个线程跑起来,理想的情况下它是100万,但实际当中呢往往不是跑一下看,3万多是吧,嗯再跑一下,ok 30000多,当然如果我们给它上锁。
就是平时我们使用的关键词叫synchronized是吧,ok上厕所跑一下,100万这就没问题,这个原因是什么呀,呃给那些个小白们,基础不是很好的同学解释一下原因,看这里最开始这个值啊是零。
然后每一次对这个值的每一次的递增过程啊,由于呢有现成本地内存,它得把这个内存昨天我也讲过啊,把这内存的一步一步拿到自己的这个呃,cp cccp和cpu核的内部做完了之后再写回来。
所以它中间是这么一个过程啊,一个线程把这个值拿过来,拿到cpu内部零,然后给它加加变成一一呢,再给他写回去是吧,这是这个加加的过程,那这个过程的话呢,为什么我们没有上锁的时候。
为什么我们没有上锁的时候好,他就会造成远远小于100万这个现象,原因是什么呀,原因是如果有一个线程从零这里读过来,变成一好一还没有来得及写,回去的时候还没有来得及啊,然后另外一个线程把这个零六读走了。
他也把这个零变成了一做加加操作吧,然后他也往回写,还没写的时候呢,又有另外一个线程把这个零读走了,所以你看啊加了三次,最终的结果呢全是一是吧,加了三次,最终结果得到了一ok这就是不上所说的情况。
这东西的本质呢,实际上是并发执行所引起的数据不一致,说点专业名词啊,就是并发执行所引起的数据不一致,那什么叫并发执行啊,就是加加这个操作实际上有好几部构成,第一个线程执行加加的时候。
另外一个线程还没等第一个线程执行完,他就进来开始运行了,这两个是并发执行,这两个线程还没有完,第三个线程又来了是吧,三个线程并发最后的结果只得到了一个一,处理这件事情。
想要得到我们期望期望的这个结果该怎么办呀,最简单的办法是把这个加加操作呀,给它变成序列化的,就是我中间不让它并发,什么意思啊,听我说,就说我这个加加操作必须是这个线程执行完了,我加完了写回去。
写完了写成一了,来,你下个线程再继续,你读的时候一定是从一读回来改成二,然后你下个线程再继续二,二回来改成三,也就意味着啊从这个加加操作呢,从原来的这种并发性的,好多人同时在执行这段代码。
变成同一个时刻,只有一个线程执行,执行完了之后,另外一个线程才能执行好,这里面也上一个概念呢,叫做原子形,昨天我给大家讲了可见性,给大家讲的有序性,今天的重点就是原子性,什么叫原子性啊。
其实就是说这个操作,我把它视为一个不可分的原子,当然你还可以写第二句话啊,只要写在这个sychronized内部的,都可以视为一个原子,这个原子的意思就是说只有一个线程执行,执行完了。
另外一个线程才能执行,所以呢这线程的执行会变成序列化的方式,它会变成这样的方式啊,有呢这是第五个,然后才是第四个啊等等,但是从时间角度的话呢,一定是第一个完事了,第二个,第二个完事儿,第三个。
第三个完事儿,第第五个,第五个完事儿,第四个,所以从时间角度它是序列化执行的,这就意味着呢我的中间的这个任何的操作,它是具备原子性,就是不被其他任何线程所打断,不被打断的意思就是说我在执行的过程之中。
另外的线程不能执行好这个概念,大家听懂了吗,能听明白,老师扣个一来嗯,没问题吧,嗯ok ok好,比较简单啊,比较简单呃,这入门入门级别的小程序啊,你们学java的一定是学过学别的语言的,也一定学过好。
下面我们来解析这个synchronized,它的本质是什么,有没有其他的方式,我们能完成原子性操作,保证整个数据的一致性,我可以不保证原子性,但是我要保证数据的一致性,可不可以,完全也可以啊。
好多种方式,我们首先来解析什么呢,一个非常基础的概念啊,就是说这个synchronize,这东西到底是个什么样的东西,大家都知道这个synchronnet写法往往是这么写的,我们在这写啊,随便给一个吧。
o object o等于new object,我们这样写synchronize o是吧,然后呢诶下面一大堆操作,这样的话呢,我们下面这些操作呢就是原原子性的操作好,这个o会帮会被我们当成一把锁来使用啊。
这就是锁的最基本的概念,什么是锁呢,这玩意儿呢就是我们经常用的一种锁啊,这个o就是那个那个锁啊,在java里面任何对象任何对象我再说一遍,任何对象,都可以被当作锁来使用,你随便哪个对象好吧。
都可以被当做锁锁的概念呢,我们日常很容易理解啊,比如说某个人想进厕所干点事儿是吧,然后那个一定是进去之后呢,这就是我们那把锁,本质上来讲,就是这把锁保护着他整个干这个事的过程,如果没有这把锁的话。
他干到一半的时候,没准其他人进来,两个屁股怼在一起也是有可能的,听懂了吧,所以说这把锁保障了我们他干这件事的原则性,只有等他干完别人才能干,你不能说这边正干的时候,中间就进来了啊,这不行。
所以日常生活中这把锁我们很容易理解,但是java java语言里面这把锁呢,大家理解起来可能稍微困难点,就是任何一个对象都可以当成一把锁,在这把锁上执行的任何的方法,同时只能有一个线程,啥意思呢。
比方说我在这里写了一个scho,我在另外一个方法里,另外一个地方,假设别的方法里啊,static的方法,我们呢,锁的只要是同一把锁,也就是同一个对象,看这里,我简单写啊。
比方说在这里他写的又是synchronized o,然后又写了一段其他代码,那么这两段代码能不能够同时执行啊,当然是不可以好吧,等在同一把锁上的这样的代码,同一个时间点只能有一个执行,一个执行完。
其他一个才能执行,这点大家能理解吧,好那这边锁的本质是什么东西呢,它是怎么实现的呢,今天给大家做一点简单的小实验啊,让大家认识一下,就是说java里面是怎么运用这把锁的,好吧嗯好。
刚才讲这里这这这一小段大家能跟上吗,能跟上给老师扣一栏,没问题啊,这样啊我我我带大家做一个小小的认知,这个我不知道大家了不了解啊,就是一个对象在内存中的存储布局,到底长什么样,这什么意思。
就是说当我们new出一个普通对象的时候,这个呢大家应该知道啊,就是当我们new出一个呃普通对象来的时候呢,这个对象它在内存里面分配一个空间,这空间呢到底有多大,结构是什么样子的,他问的是这个问题。
也是美团的祁连问之一,一个对象在内存中的存储布局呢,在hot sport的它的实现里面是这是长这这样啊,它一共有四部分构成,这四部分呢是面试的重灾区,尤其是大厂面试的重灾区,往这看,首先呢这是第一部分。
第一部分呢它的名字叫mark word,中文翻译过来叫标记字,但是我觉得你们就别记这个中文名字了,就叫mark word,记住就行,它的大小是八字点八个bytes,记住啊,大小是八个字节。
第二个呢叫做类型指针,就class pointer,class pointer的意思是说我new的哪个对象,它指向这个对象所在那个类,比如说啊我们new的是一个object。
那这个class pointer是个指针,它指向谁呢,指向object。class啊那个类型o,然后使它的实例数据就是它成员变量,最后一个叫对齐,关于对齐的概念呢,很多人老是尤其是没有计算机基础的啊。
老理解的特别费劲,简单说呢就是对得整整齐齐的,由于前面的各种数据对起来呃,有有可能呢比较乱是吧,最后要求就是整个对象的大小能被八字节整除,能被八字节整除,听懂了吧,我简单说。
就是前面你比方说前面这三部分加起来,如果只有12个字节,它不能被八整除怎么办,后面放上四个,这几个概念大家能能能能跟上吗,再重复一遍啊,第一个mc word macworld,我一会给大家讲。
这是面试重灾区,重中之重,第二个呢是class pointer,指向这个对象所在那个类啊,第三个呢是它的成员变量,第四个是对齐,所以整个长度要被八字节整出嗯,加四倍八整除。
废话我说的是12 12+4不被八整除吗,呃那个美团里面有一个小问题啊,就是美团的美团的那个七连问啊,曾经有一个小问题,大家来读一下,看一眼,可能新单位的第一个小问题啊。
就是说看这个啊叫object o等于new object,在内存中占用多少字节,哈哈这是他的一个小问题,好我们通用小工具呢来认知一下,看这里啊,我在这里呢new了一个object,我教大家使用一个工具。
这个工具的名字叫j o l,这是它的全称,全称叫java object layout是open jdk提供的,随便百度1下就能知道它的用法,在maven里面引入进来,就能用这东西用来干什么的。
用来查一个对象在内存中长什么样,看这里plus layout pass,instance,pass是解析,instance是对象,解析某个对象解析哪个对象,解析o这个对象,two principle。
把它转成可以打印出来的格式,再把它打印出来,来认知一下一个简单的小对象到底长什么样,好同学们讲到这儿还能跟上吗,能跟上给老师扣一来,搞点反馈啊,咱们小直播间的没人跟得上吗,只有麦田一个人吗,跑一下。
假如有人跟着费劲呢啊那个反馈出来,这个工具会让我们看到一个对象,在内存中的真实真实的布局。
这你能看到它的零和一的布局,看到了吗,这就是你的内存之中把一个对象new出来之后,它就长这模样,一个object对象长这模样,八位八位八位八位八位啊,前面零特别多的这八,这八这八个八位就是八个字节。
就是我们的什么呀,就是我们的mark word标记字,这八个,这四个这四个啊,这四个这四个这个加起来就是我们的mark word,那么后面这部分是什么东西啊,后面这部分是class pointer。
还记得吧,那么它指向谁,是一个指针,指向谁啊,指向谁,指向object。class,呵呵对没错,然后最后这四个呢,前面一共是12个字节了是吧,记住啊,类型指针四个字节,mark word是八个字节。
加起来是12个,我们讲不能被八整除怎么办,后面补四个,这里后面是补的四个啊,嗯比较简单啊,不太难,这样我给大家做一点小练习吧,看看能不能够理解的了,我们随便定一个class t。
我在这里写t小t等于6t,我们把这个t进行分析来,谁能告诉我这个t占多少个字节,告诉我一下,思考一下这多少个字节啊,16个对没错啊,说的很对,往下看,还是那句话啊,就是我们看啊。
就是它前面那八个字节永远是mark word,后面这四个字节呢永远都是class pointer,12个不能被八整除,它也没有成员变量是吧,它内部没有成员变量,所以呢再给它补上四个,让他被八整除就行了。
o,来看这里,ini来同学们告诉我,如果我这个时候把这个题弄出来,它占多少个字典,为啥要把被被八整除,对齐之后,管理对象比较好好好管理,如果你实在理解不了,你就想往一艘船上使劲的装袜子。
大米各种的东西这么散着装好,还是把它装到集装箱里,比较整齐地堆放好,好,好啦,这里是多少多少,8+4+4,怎么还有20的呀,咱们说一个对象的大小,它至少应该被八整除,你你给我写20是几个意思。
还有写32的是几个意思,一个int类型是多少,int类型是四个字节对吧,认识一下啊,它前面八个字节永远是我们的mark word,中间这四个字节永远是class pointer,一共是12个嘛。
12个呢,这12个一般被我们称之为叫对象的头部,叫object header啊,然后int类型多多少四个字节,对不对,所以一加正好16个默认值,看到了吗,零所以,16个字节比较简单啊。
好我们再来做个小练习啊,lol来告诉我一下这个对象new出来多少个字节,首先你想想看一个long类型占多少个字节啊,露脸雄这八个字节对不对,原来16个再加八个,24个嘛。
你这个为啥又被八帮助我解释过一遍了啊,你不认真听,你老老让我重复说,这顶得住吗,嗯漏了就是八个字节啊,看这里啊,我们再来一个啊,来一个稍微难一点的,来哪位同学知道我这个对象应该占多少个字节。
有人说是32,我们看这个小直播间,有人说吗,32,24加八三十二,跑下看看是不是32,好看这里啊,呃前面那四个加四个,再加四个什么对象头是吧,这个不说了啊,不重复了。
四个字节的i8 个字节的l一个字节的布尔,也就是说在java面呢,布尔类型实际上占一个完整的字节,那加起来是24,加一是25,不能被八整除怎么办,后面补七个,补到32,看懂了吧,比较简单。
来再来一个终极难度,这个对象占多少个字节,嗯32 40数吧,数什么数,这个字符串长度吗,这是jdk几有关系吗,只有指针嗯,32啊,大多数同学还是比较明白的,我们跑一下看看这里啊,string有三个常量。
吃三个字节,我也是醉了,看这里啊,首先12个字节的头八个字节,mark word,四个字节class pointer,这不说了,接下来呢四个字节的int,八个字节的long,一个字节的布尔。
三个字节的对齐,注意我们这个s占多少,string类型的,这是一个引用类型,是个指针,这是一个指针,后面的这个字符串,并不真实存在于我们这个t对象内部,也就是说我们new出这个t来的时候。
在这个t内部只有谁呢,只有i有l有b有一个小s,这个小s指向常量池里面的字符串,http哈马上变点com指向这个串,这个串并不真实存在于我们这个对象内部,也就是说,你只要知道这个指针的长度是多少就行了。
这个指针长度是多少呢,指针长度是四个字节,在默认的64位虚拟机开启压缩的情况下,它的长度是四个字节,所以看懂这布局了吧,这样的话呢美团的这个关于布局的问题,你就应该能理解了啊,好讲到这里。
这块没有问题的啊,给老师扣一,我们继续好吧,我们主要是讲锁的,我不是跟大家讲这个布局,就顺带着给大家补一补一补啊,下面我们把这把这些复杂的东西全去掉,我们把这个最简单的东西当成一把锁来使用。
当成一把锁来使用,本质上是个什么东西呢,我们做一个小小的对比实验就可以了,往这儿看,t小t等net,这是他刚刚new出来的时候,内存的布局情况,接下来我们给他上把锁,就是把它当成一把锁来使用。
而且锁定它,然后我再把它的布局再打印出来,看锁解开之后再把它的布局打印出来,看跑下看,我们跑跑看做个小小的对比,对比一下这三种情况,看看有什么区别,来各位同学自己自己仔细做对比,这是最开始的时候。
对象刚刚new出来。
这是这把对象被锁定的时候。
被当成一把锁来使用,并且我们锁定它,看出区别来了吗,兄弟们,这是这把锁被释放了的情况,这三种情况你自己做对比,能不能看出区别来,头部一样断着,所以在java里面呢怎么实现一把锁呢。
这把锁的信息记录在什么地方呢,我相信你就应该有答案了,mark word的作用非常重,要,就是在我们整个对象的脑袋上呢,这部分内容,对象脑袋的这部分内容啊,这部分内容就是mark word这部分。
这部分的作用特别重要,我们平时讲说呃,我们把一个对象当成一把锁来使用,我们讲的很简单,那这把锁怎么来使用它啊,实际上在这把锁的内部呀,记录着是谁,你说哪个县城,哪个县城的id,他锁定了我持有我这把锁。
比方说你进厕所之后啊,脑门上写了名字叫小壮,这个小壮啊,就把这个信息记录在这把锁的脑袋上,记录在mark word里面,听懂了吗,然后呢,当别人去申请这把锁的时候,发现这把锁已经被小壮持有了。
他怎么办呀,等待等着扎扎实实在旁边好好等待,所以呢在java之中啊,关于锁的信息,它是记录在对象的头部,头部什么地方呢,mac word里面,这小这个小知识大家听明白了吧,只用四个字节。
对目前他只用了四个字节就够了啊,呃mc word比较复杂啊,它里面呢有三大类信息,一类是关于锁的,一类是关于垃圾回收器的,这个就更复杂了,我就在这就先不展开了。
那个这个主要跟那个呃坑这个这个这个cm s,那个垃圾回收器有关系啊,呃然后那么第三个呢是关于他的hash code啊,这点可以给大家做个小实验啊,就比较好玩,你这个你自己看看就就就就就可以了。
大家看这里啊,呃同样的我们打印这个小t的信息,最开始的时候呢是这样子是吧,我们只要调用一次它的t的hash code,只要只要调用它一下啊,然后呢再打印一遍,好接着看,诶你对比一下结果你自己做对比。
这两个你会发现呢,我没我虽然没上锁,但是我掉了还是扣的,诶,它内部也发生了变化,说明什么呢,说明他的hash code也是记录在我们的mark word里面,因此这mc word有三个作用。
第一个呢是记录垃圾回收器的信息,第二个记录锁信息,第三个呢记录hash code的信息啊,ok嗯关于microworld的简单认知,我们就认知到这,今天我们主要讲,所所以呢呃我们当我们讲到这里的时候呢。
关于synchronize这把锁的一个基本的构图啊,基本的影像我们就给它勾勒出来了,相当于什么呢,相当于这里确实有个有个对象扔在这儿,然后呢我把这个对象当成一把锁。
我sychronized锁定它当成一把锁的时候,比如说我上来之后呢,夏鹏飞啊这个线程,然后呢持有了这把锁,他会把自己的信息啊记录在mark word里面,把这里改一改,说这这把锁归我了,各位兄弟们。
然后夏鹏飞呢就开始去里面干事去了,大便小便是吧啊啊这个吃饭外卖啊等等,在里边呢干一大堆的事儿,那么在他里边干这些事的时候呢,这把锁由于一直被他持有,其他的人来了之后呢,是不能够进去干这些事的。
是不能够去执行这段代码的,那么其他人得等什么时候啊,得等夏鹏飞把这把锁给释放了,后来人一看哦,ok这把锁发现没有人占用了啊,那下一个人继续来,这会儿能听懂吗,嗯这会能听明白,给老师扣个一来比较简单啊。
这是java里面经常使用的一把古老的锁,的内部的执行执行执行方案,但是这个听我说,这里面呢其实还有更复杂的过程,我再讲下一个比较复杂的过程,之前给大家讲了另外一种,保障数据一致性的解决方案。
大家看这里啊,就是说我们还拿这个小程序来举例子,这小程序呢,每一个线程给它加好多好多次,然后呢还要保证它最后的结果呢是没有问题的,是吧,呃除了除了我们使用我们传统的synchronized。
上锁的这种方案之外,其实还有另外的解决方案,下面我我我教大家呢另外的解决方案,这另外的解决方案是什么呢,就是这玩意儿啊,这我不知道有多少同学用过,就是atomic类,有原子类。
这些原子类呢是来源于j u c这个包啊,j u c这个包java有体力,有tility的concurrent,这个包简称g o c,atomic atomic energy。
比如说如果我们有一个数值int类型,最开始的初始值是零,我们就直接new一个原子类型的int类型,原子类型int类型一,正常的情况下呢,我们对这个数值呢进行多线程的加加操作,比如说我每一个线程。
100个线程,每个线程呢都去执行这个m方法,这个m方法呢对我们这个值加了1万次,这家的操作叫count。increment get,这是它内部的方法啊,本质上也是一个加加操作,但是在这里头呢。
我们会发现这种写法完全可以保障数据一致,因为它本身就是原子性的支持原子性,它的所有的方法支持原子性,它的中间呢诶被别人打断了,也能得到正确的结果,它本身是支持原子性。
所以最后我们一定能得到100万这个结果,但是我们就想了说,你既然能得到100万这个结果,你内部是不是使用了一些这上锁的操作呀,是不是使用了那个sychronized,是这样的吗,来我们点进去看看好不好。
count their increment get,ok,我们点进去看一眼,看看里面有没有啊,哎走你好,这里它调用了on safe这个类,get and add int,我们再点进去跟着走啊。
跟着我跟着我思路走走,你哎你会发现它调用了unsafe这个类的,什么呀,compare and swap int掉了这个类,哎,到这里的时候已经是native了,已经是c和c加代码了,哎你跟到最后。
你其实没有并没有发现那个synchronized是吧,你最起码没有发现java里面的synchronized,没有发现,所以这玩意儿他没上锁,你发现没有没上锁,它居然最后也能保证原子性,诶。
这是怎么实现的呢,这是另外一种实现方式,另外一种实现方式,ok好讲到这还能跟上吗。
系列 6:P32:CAS - 马士兵学堂 - BV1RY4y1Q7DL
再回顾一下,由于有些人对这类可能不太熟啊,这个类呢就是一个原子类型的类,他的加加操作呀,本身就支持原子性,它是怎么支持的呢,我们去探究一下啊,我们探究了半天,我们发现它本身没有上锁。
没有上锁是怎么完成的呢,面试中另外一个重灾区,本质上可以认为是特殊的,所叫乐观锁啊,叫c a s compare and swap,int c a s,讲一下c c a s的本质,这是另外一种锁。
也可以认为是无锁啊,好多人认为是无所,知道了。
我的图图去哪里了,看这张图吧,呃我下面我们来聊一下这个cs的本质,就是它是怎么完成,怎么操作的,听我说啊,关于cs这件事呢,面试里头问的也是贼多贼多的,我希望你能掌握呃。
cs呢它的全称呢叫compare swi,或者叫compare and set,比较并设置比较便交换或者叫什么呀,或者叫compare and exchange,比较并交换都是指的一个意思。
它的执行的原理是这样子的,长这样,认真听认真听,这是我们最开始那个数值是零,然后呢我们有一个线程的拿过来在这里改成一,然后再写回去,另外一个线程,我们说保障数据一致性的话呢,等我写回去之后。
另外一个线程再继续就能保障,但是c s操作并不保证说,我中间不被其他线程所打断,那么这个时候完全有另外一种可能性,在我写回去的过程之中,它已经变成八了,它是怎么保障我的数据一致性的呢,它是这么来保障的。
好好听他做了一个操作,做了一个比较并交换的操作,这个比较并交换的操作呢是这么做的,这是原来那个零,我这线程把它读过来之后,改成一,我一往回写的过程之中做个操作,看看你是不是依然为零,依然为零。
那如果你依然为零,说明你没有其他的线程把这个数值改变过,那我就直接把你改成一就可以了,所以就是可以这么可以理解为,当我们往回写的过程之中呢,我们做了一个判断,说if你这个值啊是不是依然为零啊。
如果你依然为零啊,那就把你改成一,这就是比较一下,并且再重新设置,是这个意思,那个同学可能会说了,那老师他他已经被别人改过了,怎么办呀,他已经改成八了,改成八个没有关系,就说明我们这次递增的操作失败了。
我就把这个八读过来,读过来,改成九,往回写的过程中判断,哥们儿,你是不是依然为八,如果你是依然为八,我就把你改成九,那有同学又改成100万,别人改了,我把这100改过来,改成101。
往回写的过程中判断你是不是依然是那个100,如果是那100改成101,如果不是一直操作到有一次成功为止,一个死循环,一个while循环啊,跟着你不停的循环,哎哥们儿,你是不是原来那个数,如果是改回去。
如果不是,来再来一遍,听明白了吗,来这块能听懂的,给老师扣个一,就是乐高所的本质对,是的,比较并交换对,这就是他的,这是怎么保障那个数据数据一致性的,就是这么来保障的啊,当然关于cs呢面试的重灾区嘛。
他一定问的问题不会这么简单,当你理解了原始的问题之后啊,他首先会问你第一个问题,就是cs里面著名的a b a问题啊,什么叫a b a问题呢,就是说你看啊有一个零,然后被一个线程拿走了。
改成一一往回写的过程之中,他看到的依然还是一个数值为零,但是这个零有可能是什么呀,有可能在他拿走改的过程之中,这个零被另外一个线程改成了八,又被其他线程改回成了零,所以这个零确实是那个零。
但是中间经历了一个过程,就是从0~8又回到零的过程,这是有可能的,这是a b又回到a的问题,叫aba问题,这块能听懂吗,比如说这是如果这是这是一个简单数值,所以呢只要它是那个零的值就无所谓。
那如果是一个引用类型呢,原来只像一只猫,一只黑猫,然后中间它指向了其实指向了一只狗,做了很多操作,回回来又指挥成了一只猫,这个时候就有可能引发你程序的不一致性了,所以a b a这个问题。
你是需要想办法去解决它的,你可以解决它,也可以不解决它,取决于你实际当中的运行情况,呃,那么如果你想解决它,前两天才问是吧,看292945说对,如果你想解决它,怎么解决它呢,解决它办法呢非常的简单。
就是给它加一个版本号啊,再加一个version version,理解这件事情很简单啊,这是你的男朋友boyfriend啊,你要出差了,你担心他出点什么事,你在他脑门上给他写一个一点,然后主持人走了。
回来了之后呢,你看一下是不是你依然还是那个男朋友,如果你发现他脑门上一点没问题,就是如果你发现他脑门上已经写上了,99点,那么说明在你离开期间,一定他经历了某些事情能听懂吗,就是给他加个版本号就可以了。
ok嗯懂了是吧,对这个版本号这个版本号啊有两种方式啊,就是第一种是使用数值,比方说一经历过一次就是二,再经历一次就是三,就是你不钻递增,这是一种,第二种呢就是你你你你可以用布尔类型啊,你在他脑门上写。
当你离开的时候,你写true啊,它是true,然后当你回来的时候,如果它变成了false,至于中间多少次,那就不管了,这是另外一种java本身提供,嗯这比较简单很容易理解啊。
java本身它是提供现成的类的。
比如说我们看这个叫atomic stampreference,这个stamped所代表的就是版本号的意思,好吧,atomic stamp reference k使用布尔类型,中间两个线程改了怎么办。
那我说了,你使用布尔类型代表你自己不在乎多少次,只要有人改过就变就变成false了啊,变成非处了,这种呢是是是是带版本号的,那么另外一种呢atomic markable reference。
那么这种呢是布尔类型的好吧,布尔类型啊,initial mark可以是true,可以是false,所以你来这块大家听明白了吗。
怎么怎么解决这个aba问题,这是第一个问题啊,就是aba的问题,就是加版本号就可以了,就这个代码是我们的vip的代码,这个代码是不给的好听,我说第二个问题会非常容易被问到的,第二个问题关于cs的。
认真听这个问题才是致命的问题啊,很多时候问到这个问题的时候,对cs一知半解的人就开始就开始犯傻了,犯糊涂了,cs呀,他就问你,他说哥们儿,你这个最后一步呢,c最后一步是什么,我们分析一下。
就是从零变成一,一往回写的过程之中呢,判断一下再再进行修改吗,就是if哥们儿,你是不是依然还等于那个零,如果还等于那个零,才能把你变成一,那么假设我在判断完了,我已经判断完了,确实你为零。
我还没有来得及把你改成一的时候,你这个值被其他的值修改成八了,这不就又出问题了吗,听懂了吗,兄弟们,这个问题o我再重复一遍啊,就是说他会问你,他说你这个cs最后一步的操作。
不就是说我判断一下你是不是原来那个值,如果你还是原来那个值,我就给你改成新值,如果不是原来的值,我就再来一遍,不就这个操作吗,那我判断你这个值是原来那个值,我还没有来得及改成新值的时候,被别人打断了。
同学们这个呢就需要cas操作这一步操作,这一步操作他自己要保障原子形,中间不能被别人打断是吧,同学们好,那这个那这个他是怎么完成的呢,底层还是上锁,对这个要看它的底层的话呢,呃后面你别走神儿。
有决心往下挖掘一下的,给老师扣一,我带你稍微的挖掘一下,这个稍微有点麻烦,别走神啊,没关系啊,就是跟不上这个过程的,可以最后把结果记下来好吧。
大家仔细看啊,嗯当我们要探究它背后的执行的原理的时候呢。
一般的情况下我们去分析它的代码对吧,分析它的源代码,它源代码是什么样呢,就类似于像这个atomic integer这样,他本身用的cs,那么它是怎么完成的呢,我们点进去看,我们点进去看。
我们点来点去呢会发现它进入到了哪个代码呢,进入到了native代码,native是c和c加加写的,那么这个能不能跟进去,答案是可以啊,这个过程呢,其实跟这个native代码的过程比较复杂。
我在这呢就带着你呢简单带大家读一遍好吧,就是我们要知道他最后调用了是一个c和c,加加的compare and swap in的代码,这个类的名字叫unsafe。
unsafe o,如果你能找到,jdk他c和c加加的代码啊,这个open jdk是提供的,你自己可以去找,你可以找到这个类,这个类那叫unsafe。c p p,这个明显它是一个呃c加加的类。
ok然后在这个类的内部compare and swap int,在这里方法在这,你可以理解为刚才那个方法调了这个方法,那这个方法呢实际上又掉了。
atomic这个类的compare and exchange方法,当然这个要跟过去的话,那我就直接跟过去,你就能看到我们本质上的cas,它到底是怎么完成的,就这部分代码。
当然这份代码你要跟起来就相对费劲一些,我带大家呢做一点小小的解析,在这儿能跟到这里的,来跟老师扣一啊,目前还能跟得上的听大概就可以,一般的面试问到这个程度就差不多了啊,认真听认真听。
大家看这里本质上它是由这个代码实现的,compare and exchange l这东西是个什么东西啊,当你看到前面这个标志的时候,a s m什么标志啊,汇编语言对不对,这是汇编语言的标志。
也就意味着这个代码呢是汇编代码,也就意味着我们cpu本身它支持一个指令,这个指令呢就叫做比较并交换,也就意味着这是一颗cpu,这是一颗cpu,如果对我们内存里的某一个数值,进行修改的时候。
这是内存的某个数值x对它进行修改,我可以有直接修改的方式,也可以有cas方式进行修改,把你拿过来改成一个值,改完一个值之后呢,比较一下,你是不是原来那只是原来那只再给你改,不是原来那值重新拿过来再改。
这个大家能听懂吗,没问题吧,所以说呢硬件指令本身就支持cs操作,这是我们的第一个结论,但是各位同学硬件知识的操作,未必意味着这个操作具备原子性,我再重复一遍,即便是你cpu直接支持的指令。
也并不是说你这个指令本身就支持原子性,完全有可能发生一件什么事情了,就是当我第一个cpu在改这个x的时候,我把这x拿过来改成x加一,往回写的这个过程还没有来得及写的时候。
另外一颗cpu把这个x已经改成别的值了,改成x加二了,听懂了吗,完全有可能,所以这个操作本身不具备原子性,那回到了那个悖论了,就既然你不具备原子性,那你cs操作还是有漏洞啊,那怎么办。
所以在这个操作前面最关键的代码在这儿,在这儿叫lock if mp啊,在这volatile,你们跟着volatile是这是c和c加加里的volatile,往这看,他最关键的代码在这啊。
叫lock if mp,那么这段代码怎么去理解它,好记住这条指令了吧,就是说底层指令支持,这是第一,这是第一个结论,但是这条指令本身不具备原子性,我想办法让这条指令具备原子性怎么办。
ok这里呢是一个红操作,做一个替换就可以,这宏操作里面比较复杂,你别的不用看,只要看这条指令就可以,这条指令叫lock好,这个红的叫lock if mp。
他说adding a log preface to an instruction on mp machine,mp什么意思呀。
mp的意思就是multi processor,相当于就是你你多核的,如果你有多个核,我就前面给你加一条指令,lock lock指令,所以最终的结论呢我们就得到了,昨天给大家分享的文档里也有。
你呢也可以打开文档看啊。
昨天给大家分享的文档final。
昨天给大家分享分享的文档也有,在这个文档里呢,呃我教了大家怎么样去跟踪cs啊,怎么样去跟踪cs,从cas读到on safe,从as unsafe呢读到unsafe。c p p,从on save。
cpp呢,找到我们的lock if mp是吧,找到这里,从lock if mp呢我们得到最终的结论啊。
这里是最终的结论,各位同学只要把这个最终的结论记住就可以了。
刚才那段你跟得上就跟跟不上,记住最终的结论,我们所有的cs操作在hot sport这个虚拟机的情况下,它本质上是由这条指令来完成,这条指令叫叫log compare and exchange,好。
怎么理解这条指令,只要现在能都能跟上吗,兄弟们有没有跟不上的,能跟上,给老师扣一,跟不上的呢,你有什么问题直接提啊,下面我们来聊怎么理解这条指令,这条指令怎么去理解它呢。
首先呢后面这条指令呢我刚才讲过了,你应该能理解了啊,这是一颗cpu,这是一颗cpu,通过这条指令可以cs操作去改某一个数值x,然后呢,前面这条指令是关键点,前面这条指令的关键点是说。
当我执行后面这条指令的时候,不可以被其他的cpu或者其他线程所打断好了,这是一条lock指令的含义,lock的含义听懂了吧,当然我讲到这儿,很多愿意刨根问底儿的小伙伴,他肯定不开心。
老师你告诉我他是怎么保证这一点的呀,怎么保证他不被打断的呀,各位同学,保障一条指令不被打断,从硬件层面上来讲,它有好多好多的方式和方法,这里面它内部升是一个升级的过程啊,我就在这就不展开了。
它有哪些方式和方法,第一个呢叫关中断,如果你学过微机的原理,你就会知道,我们所有的操作都是通过中断来完成的,在我们的操作系统这个级别上啊,cpu这个级别上都是通过中断来完成,就说我执行这段代码的时候。
我根本就不想用任何中断,你任何人都可能不可能打断我,所以第一个叫关中断,第二个呢叫缓存锁,昨天我讲过缓存的概念,就是把整个缓存行x所在缓存行全部锁定,我改的过程中不允许任何人进行任何修改。
这个可以不可以,完全也可以,但是有的时候x可能数值特别大,都超越整个缓存行了,你这时候怎么办,所以第三种第三种叫什么,第三种叫锁总线,锁总线,什么叫锁总线,就是我把这个通道给锁住。
当我执行这个操作的时候,只允许我这颗cpu去访问这个通道,其他谁都不可以怎么锁,拉高芯片上的北北桥芯片的一根一根电平,往上拉高就可以了,好了就讲到这里啊,再往下讲的话呢,我觉得给你探究硬件了。
还能跟上吗,兄弟们懵逼是吧,懵逼就算了啊,我们回顾一下啊,把前面把前面这部分稍微回顾一下,稍微回顾一下,梳理一下,我们再继续往下o,什么意思啊,认真听我们所有的语言。
所有语言虽然说我以java语言来给你举例子,但我讲的东西不限于java语言,c和c加加本质是一样的,他的所有的说呃,内部的这种语言,所synchronized的什么什么什么什么。
实际上呢是把任何对象都可以当成一把锁,在某个位置,在java里面是在他的mark word上记录着这个锁的信息,是谁持有了这把锁,我我把它释放开了之后,另外才可以,这是我们日常使用的锁。
一般我们把它称之为叫悲观锁啊,就是上来之后二话不说,我先把我名字记上,先锁住啊,我其实你想想看,有的时候你进门上厕所,你是不需要上上锁的,是吧啊,你在家就家里就你一个人,你不用上锁,对不对。
但是呢我们上来就给他上锁,表示自己很悲观啊,我我我管他呢,我悲观的认为一定会有人来,所以我上来先把锁锁上,这叫做悲观锁,那么第二种方式呢就是cs,它是乐观锁的一种实现方式,本质上他认为呢在我改的过程中。
不会有其他人对他进行修改,那么如果有其他人进行修改了,我就采取补救措施啊,我零已经被别人改成八了,没关系,我把八拿过来改成九啊,写会计的过程中,八又被别人改成100了,再拿过来改成100。
一直到有一次成功为止,那么它的本质实现实际上也是悲观所实现,所以就是说所归根结底只有一种就是悲观的啊,这个没有办法啊,它的本质实现呢我们一层一层的跟下来之后呢,你会发现它掉了unsafe。
unsafe下面呢它掉了c和c加加的on safe,对吧,我们会发现了一条指令叫compare and exchange,表示它cpu级别直接直接支持一条指令,但这条指令本身不具备原子性。
我们怎么保证它原子性啊,在硬件层面我们加这条lock指令,这条指令就可以保证,这条指令内部是怎么实现的呀,一共有三种方式啊,这个内部是一个升级过程,太复杂就不展开了,ok基本上我以前遇到的面试。
就问到这个程度了啊,没有比这个更深了,好讲到这里我们可以继续的给老师扣一了,大家可以从笔记里头找到老师的这个跟踪过程,好吧,虽然说你可能不知道怎么去搞那个,hosport代码之类的。
咱们v i p呢是有一些hosport代码,讲给大家听的啊,比较关键的代码呃,有就是那个那个满足,有一部分呃,比较想深入了解底层的兄弟们的胃口,是这个意思啊,但是对于大多数人来讲呢。
你跟跟着我差不多走一遍啊,然后记住结论基本上就可以了,呃大多数面试官呢基本上就就搞不定你了,听懂了吧,嗯好嗯,ok ok好,那你理解了这件事情之后,当你列了这件事情之后呢。
下面我们来看另外一个理解了这件事,我们就可以深入的理解synchronize的关键词了,就这个文件字啊,就synchronized,大家平时都老用老用老用,现在你明白这是怎么使用的了。
但是synchronized的内部是有一个所升级的过程,这也是面试的重灾区之一,就是c synchronized的内部是怎么进行所升级,也叫所优化的,我们讲一个锁呢,如果你上来二话不说。
就拿一把锁挂机关注之后就开始用,那么它效率一定很低,原因是什么呀,原因是同一个时间点啊,这个坑只能一个人用吗,对不对,我想提升整个锁的效率,我该怎么做,它内部帮你做了一系列的提升哇,这个又又又又又复杂。
有的讲了啊,好看,这里读没必要锁毒没必要,锁也有,有的时候也有必要,你读的过程被别人写了怎么办,锁呢有好多好多种啊,讲了基本的悲观所,讲了基本的乐观所,实际上在我们没有j u c这个包之前。
大多数因为用的锁就是synchronize,也没有其他没有其他可以选,但是我估计应该有很多人了解过啊,实际上j u c包了出来之后呢,有好多种其他的锁了,就比如说reentrance log是吧。
这个就是用来替代synchronized,还有什么呀,countdown latch门栓,ok它的本质也是用c a s来实现的,ok还有呢sec liberrier栅栏是吧,per阶段同步器。
ok刚才有同学说读不用上锁,本质上都是有些毒是需要上锁的,万一被别的鞋所改变了呢,你读的不是一个中间值了吗,就成了对吧,所以呢read riot读写锁,ok还有summer信号锁。
还有呢exchanger是吧,交换器以及呢比较好用的这个lock support啊,所支撑,还有呢stem lock啊,这种的是不可重入锁呃,steplog呢是唯一的一个不可重入锁啊。
其他的基本上没有不可重入锁啊,呃j o c提供了很多很多线程的锁,你可以直接拿来使用,j o c呢也提供了自己的那个锁,构建锁的基础要素,你也可以愿意的话,可以自己构建,比如说你自己写一把锁啊。
em lock我就是星期二上锁,其他的都不上锁,哈哈也可以的,本质上你都可以用自己的想法来实现好吧,这块呢也是面试的一个重灾区,但是今天我们就没法展开了,我们今天先讲,先讲所的本质好吧,相比讲所的应用。
系列 6:P33:锁的升级:偏向锁未启动 - 马士兵学堂 - BV1RY4y1Q7DL
下面呢我们来聊什么呢,就面试中常问的另外一个问题就是锁升级,索隆提是一个很很细节的过程,今天我给大家聊一个初步的脉络和梗概,大家看这张图,记住这张图就是synchronized的内部,所执行的流程图。
synchronized,当你new一个对象出来,刚刚开始new出来的时候,它会是一个普通对象,如果你偏向锁打开,它会是匿名偏向,如果是偏向锁打开了,第一步锁定的是偏向锁,第二步锁定的是轻量级。
第三步锁定的是重量级啊,中间有一个升级的过程,好了来,下面我们要准备对这幅图进行细节的展开,准备好的同学再给老师扣一,嗯嗯好的,大家认真听,偏向锁概念相对复杂一点,我们先扔一边。
下面我们首先首先来理解什么是轻量级,什么是重量级,好各位同学听我说这个轻量理所呀,就是我们刚才讲的这个cas的概念,ok,这个清掉你所就是cn的概念,也就意味着在synchronized的内部。
执行的过程之中,实际上它有一步呢是在做这个轻量级锁的操作,现在你所的意思就是说啊,我们还拿那个上厕所来举例子啊,哥们儿有一哥们在里面上厕所对吧,现在你所是怎么操作的呀,轻量级锁的操作是这么操作的。
有一个人已经进去了,然后呢门上贴着他的名字是吧,这门上是叫铜墙铁壁,然后如果有人来了,用轻量级锁的方式来热竞争,cas循环不停的循环,while循环怎么循环啊,简单理解为就是拎着裤子跟着原地转圈。
每转一圈看看锁开了没有,每转一圈儿看看锁开了没有,什么时候发现锁开了嗯,比如说,来比如说这上面坐着的人是铜墙铁壁是吧,然后来了一个人叫夏天,夏天就开始拎着裤子跟他转圈转一圈,哎,哥们儿你出来没有。
哥们儿你出来没有,然后又来一人l b p也跟着拎着裤子转圈儿,哥们儿你出来没有,你出来没有,什么时候发现门一旦开了,或者锁被打开了,这两个人一拥而上,看看谁先抢到,谁先抢到。
比如说夏天抢到了夏天进去干事,lb hero在这里继续拎着裤子转圈,唉,转每转一圈开了没有,每转一圈开了没有,直到开了位置啊,听懂了吗,这就是那个轻量级锁的,用cs实现了一个简单简简单的理解啊。
就是这么来理解,ok来这块听明白,老师可以啊,好这是轻量级锁啊,下面我们来理解什么叫重量级锁,各位同学,重量级锁这件事情呢相对难一些,理解重量,你所就需要理解另外一个概念,认真听啊。
我发现需要补的基础概念,大家伙应该是比较多,没办法给大家补一补,稍微,就是线程模型啊,我们讲这个线程模型啊,好大家看这里看这里啊,我给大家画一下图就行了,那么这是我们的操作系统dos大家都知道啊。
我们的虚拟机啊是跑在,我们的虚拟机呢是跑在操作系统里面的是吧,我们我我们虚拟机啊,这是我们那个jvm,这个m呢是跑在操作系统里面的呃,关于对于cpu的各种调度,对应的操作系统啊。
其实就是操作系统里面的线程,这是操作系统的线程,操作系统限制操作系统线程好,现在问题是呢,大家都知道我们在jvm里面,我们也可以写自己的线程,对不对,在jvm内部啊,我们也可以写自己的线程好。
这是jvm的线程,现在我问你的是呃,jvm写一个线程应该大家都会写吧,thread等于new thread就new出来一个线程,对不对,下面我问你的是一个jvm的线程。
对应操作系统的是一个操作系统线程吗是吗,就说我在jvm里面六个线程出来,我的操作系统是不是,真正的会给他new一个线程出来,是吗啊,有人说是,有人说不是啊,答案是yes,记住答案是yes。
目前呢大多数的jvm的实现,就看具体看哪个哪个jvm实现啊,兄弟们具体看哪个jm实现,目前大多数jm实现都是这样的,一比一的关系,这里起一个,这里就起一个,因为他偷懒儿,明白吗。
如果我要自己去管理整个线程的调度,我需要单独写算法,写起来很麻烦,所以jvm呢从开始就偷了个懒,我把我所有的线程的调度,线程的管理交给谁,交给操作系统了,我这里有一个交给他去管理。
new一个交给他去管理,然后呢他再把结果反馈反馈回来给我,ok这是dvm。
那么和这个形成鲜明对比的是另外一个语言,是另外一个语言好这个语言是什么呢,这语言是go,go on的虚拟机,go on虚拟机长什么样呢,go on的虚拟机呢,记住在go里面,它的名字叫不叫县城。
叫携程啊,或者叫先城,这里面它起n多n多的携程,或者叫n多n多的线程,那么对应我们的操作系统起多少个呢,其实最多就起那么十几个,这里是一个m bn的关系,o这里面它里面执行的所有的任务。
最终是由我们操作系统的十几个线程,或者几十个线程来完成的,而这个里面的携程可以起多少个上万个,ok这大家能听懂吗,这就是虚拟机的线程模型,每一个模型有每一个模型自己的好处,并不是说go的一定好。
并不是说java一定差啊,也不是说java一定好,go的一定差,go on是这么设计的,go on呢起一个协程非常简单,一个关键词go就可以搞定了,对不对,好各位同学,这里面就意味着有一个本质的。
有一个本质的这种这种区别,这种区别是什么呢,就是我对于自己内部现成的管理,说这两个线程之间,他们之间如果想做数据同步的话,由谁来管理啊,注意是要交给我们的go的虚拟机直接管理,那对于jvm来说。
如果两个线程冲突,他们有一个做一个数据的一致性的这种呃,比方说等待在同一把锁上的这种一致性的啊,调度调度管理啊,轮到谁不不轮到谁这样的管理好,这种时候交给谁啊,交给操作系统老大,各位听懂了吗,兄弟们。
来这块能听明白的,给老师扣一,一比一究竟是一个还是还是还是两个,当然是一个呀,本质上所有的东西,所有的最终都要通过操作系统的线程来完成吗,最终就是操作系统一个线程嘛,所以你看你攻你。
你自己看你的眼神钉在哪个层次上,ok好,各位同学认真听啊,那么回回过头来,我们来看这张图。
来看这张图,这张图的重量,你所意味着什么东西,请大家记住,如果是在轻量级锁这个层面,在轻量级锁的这个层面,java虚拟机自己就能搞定,while循环吗,反正well,你not open。
我就跟着转圈就行了,是不是很简单,就在这里,java虚拟机自己搞定,不需要经过操作系统,老大,接下来如果你要交给,说我管不过来了,交给谁,重量级锁的概念,就是交给操作系统老大帮我管理。
这是重量级锁的概念,这部分我自己管,这部分交由我的上级来管,所以它比较重,中间加了一层操作,得我的老大给我反馈回来,我才能得到结果,这是重量级锁的概念,各位听明白了吗,来这会儿大概听明白的。
给老师扣个一,所以轻量级自己搞定,重量级老大搞定o,那下面的问题是,老大搞定和我自己搞定有什么区别,听我说啊,就是这个老大呀,它内部又是一个复杂的过程,这部分也是一门课,叫操作系统吧。
学过这门课的就容易理解,没学过这门课就不容易理解,不过没有关系,我给你讲一个典型的场景,典型场景是什么样子的呢,典型场景是这样的,这个重量你所管理的时候经常有一个操作,就是让人去等待。
各位同学有没有调用过这个方法,叫older weight。notify,这句话的本质是什么意思呀,这个大家知道吗,weight,进入这把锁所关联的等待队列,仔细听啊,这不是让他进入等待状态。
是进入这把锁所关联的等待队列,让这个线程一个人来了,使劲儿转圈儿,转圈的人实在是太多了,我都转不过来了,我cpu都忙不过来了,怎么办,交给我吵醒老大,我操醒了,怎么管呢,让它直接进入等待队列。
来了之后呢,这是那把锁,这把锁所关联呢有一个等待队列,一个队列,这个队列呢让这个人直接进去排队就行了,什么时候轮到你了,什么时候把你拎出来,什么时候轮到你了,什么时候把你拎出来,听懂了吗,只要等待队列。
所以呢轻量级锁和重量级所它的区别,现在就呼之欲出了,这也是面试的经常问的问题,问轻量级锁和重量级所有什么区别,呼之欲出,轻量级所示,所有的线程都活着,原地转圈儿,消耗cpu。
while循环能不消耗cpu吗,重量级所示,很多线程进入等待状态,什么时候叫醒,什么时候再执行,不消耗cpu,各位听懂了吗,这是轻量级锁和重量级锁的区别,来我上面讲完的,能跟上的,给老师扣一。
嗯有点反馈啊,确认你还在听好不好,这边就只有那个小记号还在跟着我听是吧,其他的就不跟着听了,嗯雷雨嗯,ok 7371,good,好认真听认真听好,接下来那它中间这个升级过程是怎么升级的,为什么要升级。
这里面又隐含着一个面试题,就是到底轻量级锁好还是重量级所好,有了清道理所为什么还需要重量级锁是吧,有了轻量级,为什么还需要重量级,ok y哪个锁更好,答案是各有各的好处哈哈不然的话那就没必要。
其中有一个就没必要存在了,对不对,在什么情况下我们使用轻量级,什么情况下我们使用重量级,那么你想想看,如果有这么一种情形,这哥们儿呢叫伯伯峰,肠胃不太好,吃的又多,进去之后一干就干半小时。
然后外面等待的人又特别多,1万个人在外面等待,各位同学告诉我,这时候用轻量级好还是重量级好啊,轻量级轻量级就意味着什么呀,轻量级就意味着这1万个人在那拎着裤子,玩了命的转圈。
每转一圈消耗cpu cpu发现这都是活着的现场啊,不能让他们得不到我的cpu的时间,这个也不行,对不对,所以得让他们得到时间片执行,那就意味着光线程切换就消耗了很多cpu了,效率反而不高。
而且呢我转半天圈也得不到锁,为什么,因为波波峰这哥们儿,他这个时间太长了,是不是,所以这种情况下,我们一定是让这1万个人去排队,让伯伯峰什么时候完事了,什么时候再拎出另外一个人来,再进去就行了。
这样的效率反而变高了,ok所以我们得出结论是什么情况下呢,一般来讲我们干的这件事儿,专业名词呢叫做critical section,叫临界区,临界区的这个操作,也就是你干这件事啊。
大大个便这个时间特别长,与此同时竞争又很激烈,什么叫竞争很激烈,就是等待的人很多,这种情况下不适合轻量级,直接升级为重量级,其他时候都是轻量级,这块大家大概听懂了吗,呵呵好大题,明白之后呢。
我看刚才有同学问啊是吧,老师那什么时候清量级升级为重量级啊,这玩意儿比较复杂,你们想听的看,我其实有的有点懒得跟你们讲啊,这会儿还能跟上呢,还可以往细节里揪一揪的给老师扣个。
一来就是说在什么具具体在什么情况下,轻量级升级为重量级,好吧嗯,反正就是你大概理解就是轻度竞争的时候,我们使用轻量级就可以了,现在机搞不定的时候才会升级为重量级,听懂了吧,那具体什么时候升级呢。
这里面是有它的一个指标,这个东西呢,我在那个笔记里给大家写的很清楚啊,所以说呃我是推荐各位学习呢,不要追求说我就一定上来之后,所有细节全掌握,你应该先掌握这张图的大概脉络。
然后呢再去慢慢的去探究这里面的细节,这样来学习啊,不要那个上来学一大堆细节,所以我有的时候呢还给大家讲太多的细节,主要是因为这种学习方式效率其实并不高,呃如果有兴趣去读这话。
各位看这里啊,如果竞争加剧,在这里在这里,因为这里面涉及到另外一个东西,就是呃jvm的u调优啊,就是你需要指定jvm参数,如果竞争加剧是这样的,在以前的老版本的情况下,线程超过十次自选。
就是在转圈转了十次都没轮到他,或者说自学的线程数超过cpu核数的一半,比如说你那个有有十个和十个盒,然后呢这时候数量已经有六个线头了,在这里转圈了,好这个时候呢升级为重量级,但是呢jdk一点六之后。
他加入了自适应自旋转圈,a dance of spinning,adaptive self spinning啊,跟我读啊,adaptive self spinning。
ok adaptive self spinning,这时候由由谁来控制呢,jym自己控制就行了,你不用再管了好吧,不用再管了就ok,所以这个如果你要愿意管。
你也可以自己指定啊,但是一般不建议管这事儿了,简单说呢就是这事不要不要你管了,他自己管,自己判断什么时间生,他不生来这块听明白了吧,啊关于这块我就大大概给大家讲清楚了,就是轻量级锁什么意思。
重量级锁什么意思,k所谓的轻度竞争是什么啊,什么时候转成重量级好,我们我们我们给大家讲一个比较难的概念,偏向锁好吧,嗯来准备好的同学和老师扣一,这个偏锁呀,它比较特殊,是不是从重转为轻,转不了啊。
没有没有往回的箭头,这东西只能往前走,好变t啊,这个偏向锁呢它这个概念呢比较特殊啊,这个也就是存在于面试里面,其实呢你掌握它不掌握它,我认为关系不大,为了就是有些同学的刨根问底儿。
给大家讲一讲偏向锁的概念,偏向锁,偏向锁,严格来讲并非一把锁,啥叫偏向锁,讲这个电阻呢也可以顺带着教大家,你看清楚你现在的锁是哪种锁。
呃实际上我们是可以通过一个观察,一个对象内部的结构,能够观察出来我们现在用的是哪种锁啊。
这我教大家一个小小小技巧,看这里,比如说,那刚才那个小程序来举个例子啊,比如说t小t等于6t是吧,我上我给这个小t上把锁synchront,然后呢把它给里面内部再解析一下,跑一下,大家看这里啊。
就是说这个时候啊,是我们被锁定的那个对象的内部状态,如果你想知道他现在上的是哪种锁,你只需要对照老师给你画的那张表就可以了,我们把那张表调出来,刚才那张表啊,就这张表只需要跟这张表做对照。
从哪里做对照呢,从这几位这几位做对照。
ok你看啊,你读这几位,这几位目前是000。
对不对,如果这几位是001,对应的是无所啊,我们我我,我们看那个我们那个小程序刚刚new出来的时候,是不是零一看了吗,这时候是没有锁的,等于是没有人锁定的,所以他怎么判断是没有人锁他呀。
只要判断这几位就可以了。
好我们翻过头来,那么如果你这里写的是幺零,幺,对应的是偏向锁,听懂了吧,如果这里是零零啊,我们现在就是零零,对应的是轻量级锁或者是自旋锁,或者叫无锁啊,那么如果这里是一零,对应的是重量级锁。
ok如果这里是一一,就是表示呃这是我们垃圾回收器,那这样来回收这个对象,来这块儿大概能看懂的,给老师扣一没问题吧,就是你看啊我们上来之后上的就是轻量级锁,对不对,那有同学可能会说老师。
那什么时候我能看到那偏向锁呢,看到偏向锁呀也很简单,就是你只要干这么一件事就可以了,thresleep 5000,我们只要上来先睡五秒钟,这里稍微等一下,因为他睡五秒,睡五秒之后。
你发现我们上的锁,我们看到这个对象上完锁之后呢,和原来就不一样了。
刚才你还记得吗,他是零零,是不是现在是什么,现在是101,那101什么是什么状态,对比一下101在这什么状态,偏向锁是吧,就是睡五秒钟之后啊,你发现你那个对象就变成偏向状态了,哈哈好。
下面我们就开始讲这个偏向锁的概念啊,也顺带让大家理解为什么睡五秒钟它就变偏,就变偏向了啊,后两位还是三位,两位或者三位吗,不都一样吗,仔细听仔细听这个片索呢,其实他还挺有意思的啊,挺好玩的。
给大家讲一下偏向锁,那到底什么叫偏向锁呢,各位同学偏向所最基本的理解就是一个标记,他甚至呢本质上都不是一把锁啊,它就是个标记,比如说我再举个例子啊,我拿我拿谁来举例子呀,我看看谁正好错的,错的是龙舞啊。
龙舞太不雅观了,ok龙五呢觉得很不雅观,所以呢他上锁的时候上偏向锁,偏向锁的第一个概念叫做偏向第一个线程,厕所开门了,第一个过来的人是龙舞,好了,这把锁就是龙舞的,那这个偏向锁怎么上呢。
龙五把自己名字写上龙龙五,ok把门往往门往上往上一贴,说哥们儿啊,这把这个坑归我了,进去干事好了,这个标记上面贴着的这张字条就是偏向锁,从专业角度讲呢。
就是龙舞把自己的线程id直接写在mark word里面,表示这把锁归我啦啊这就叫偏向锁,那偏向所有什么好处呢,大家都知道县城是执行一会儿休息,一会儿执行,一会儿休息,一会儿,听从线程调度器的龙五。
在持有了这把偏向锁之后,它是由于他是第一个来的,第一个来的,所以呢这把锁是偏向他龙武的,就给他写一名龙舞,不会写别人的名,只会写第一个过来人的名字啊,那龙舞呢就是你的,就是这个他的初恋对吧。
刻骨铭心的记录在这里啊,只会偏向第一个,后面的都不算,这有什么好处呢,好处在于龙舞这个线程暂停之后再回来的时候,只要他回来,发现上面写着我的名字,龙舞直接进去继续干事就可以了。
没有必要进行所竞争这块大家能听懂嗯,就是他省了很多锁竞争的过程,ok这就是偏向锁的概念,那下面我们来讨论,如果又来了第二个人怎么办,假如第二个人来了章鱼,和铜墙铁壁,这俩人来了,这俩人来了一看,哥们儿。
你你不对呀,就你一个人把坑全占了,这不合适啊,把龙武的名字撕下来,然后这三个人开始轻量级锁,拎着裤子转圈,竞争是竞争上谁就是谁的,这块就升级到了那个轻量级锁了,好吧,什么时候撕,只要有第二个线程来了。
就直接撕好,这是这个过程啊,我们再重复一下,就说第一个人来了呢,把他名字往上一贴,然后如果他再回来,就不用有所竞争,上面看就是我的名字,直接推门就进,那这个时候如果第二个人来了,我们要进行锁竞争。
谁哪有这把锁,谁才能够在里面干事儿,就把这个名撕下来,然后他们三个人开始自旋锁竞争,拎着裤子转圈,一一往往的具体的实现呢也是优先偏向龙舞啊,就是即便升级为轻量级锁龙五,也是第一个进去的啊,一般是这样的。
就偏向哦,好各位认真听啊,认真听,那么这个时候呢这把偏向锁有什么作用呢,就很奇怪啊,那有一个人来了,我直接让他去进行锁定增生,不管甭管是轻量级重量级不就行了吗,干嘛要设计这么一个标记。
设计在这里有什么用,这里面有它背后深刻的含义,各位同学,这个深刻的含义我是尝试讲出来,看能不能理解,这里面呢有一个小小的调查,就是在我们日常工作的过程之中,虽然说我们用到了某些带同步的方法。
比如说synchronized的各种各样的方法,你可能没有意识到,其实你一直在用,但是在绝大多数情况下,我们用这些方法的时候,实际上只有一个线程,在百分之八九十的情况下。
我们在使用synchronized方法的时候,实际上只有一个线程在用,有同学说老师不理解,我给你看一个最粗浅的案例,你就理解了,大家看这里,我们日常开发之中经常这么写,is out。
hello world,好,我们看了我们写了这句话,这句话里面有几个线程告诉我有几个线程,几线程,一个主线程就一个,对不对,那么你这里面用锁了吗,有没有用锁,你可能不知道rain line。
这里面就有synchronize,看到了吗,所以他实际上已经使用了锁,ok,那假如说我大多数县城,只有一个线程在使用这把锁,我有没有必要启用那种复杂的锁竞争机制,啊我判断一下谁是什么状态,该轮到谁了。
下一步是谁的,这把锁是谁的等等,有没有必要我再重复一遍,在绝大多数情况下,我们可能自己知道不知道的时候,我们就已经使用上锁代码了,那使用这个上锁代码的过程之中,的绝大多数情况只有一个线程。
那只有一个线程情况下,我们有没有必要启用一个复杂的锁定成机制,有没有必要,没有必要了,那没有必要的话,那干脆就给他设计一个偏向锁就算了,所以在你一个线程使用这个synchronized的时候。
它内部就是一个偏向锁,就偏向你这个线程,你如果没有别的线程,你在重回的时候,重入的时候永远不会有锁定争,你的效率就提高了,这就是偏向所的设计机制,来各位听懂的老师可以,那好那我们回头再来看啊。
那为什么这个偏向锁,向左为什么是最开始没启动啊,我睡五秒钟才会启动啊,为什么会这样子呢,刚才我们实验过,对不对,我们上来睡五秒,然后我们就观察到了那个偏向锁是吧,synchronized。
然后synchrono,这时候我们就观察到那个偏向锁啊,为什么我们在这时候会观察到它的原因是什么,嗯那我们反过来问一个问题,就是说当我明确的知道是多线程的时候,我们说大多数情况下是一个线程。
所以我们设计一个偏向锁,但是当我明确知道,我非常明确的知道我下面用的肯定是多线程,一定是多个线程,我有没有必要启用偏向锁,骗子组还有没有用啊,没用,反正你出来之后也要也要被人撕掉。
撕掉的过程是不是还得费一部手续,效率反而低了,一个虚拟机启动的过程会启动好多好多线程,大概十几个,明确的多线程,听懂了吗,什么垃圾回收线程啊,背后分分配的线程啊,找操作系统要资源的线程等等等等。
它会启动好多个线程,明确的是多线程,还有没有必要启用偏向锁呀,没必要,所以虚拟机启动的过程是这样子的,在最开始它不会启用偏向锁,什么时候会启用啊,默认配置四秒以后,四秒以后启用偏向锁。
这个结论呢在老师给你的笔记里,也记得非常清楚啊,各位同学,如果你要愿意,你也可以使用jvm调优的参数来自己设置,这把偏向锁什么时候启用或者不启用,这些都可以听懂了吧,看这里可以用这个参数来修改它。
这个参数呢叫biased,lockjof daily啊,跟着我读,biased就是偏向的locking锁,start up,启动delay延迟,你可以把它启动延迟设置为零,那就刚开始虚拟机启动。
它就启动了,默认四秒,好了,偏向锁我就讲到这儿啊,大体的概念我就讲清楚了吧,应该这个图看翻译出来看看,还有什么不明白的吗,一股子咖喱味,好我们再看这张图,看是不是能看明白了,来关于这张图。
还有没有谁有疑问的,好不要聊聊英语了好吧,英语浪费了我们中国人。
系列 6:P34:锁的升级:偏向锁已启动 - 马士兵学堂 - BV1RY4y1Q7DL
现在有点懂了是吧,ok我估计好同学呢可能还不知道呢,这个匿名偏向是什么意思,匿名偏向的意思呀,就是当我们new一个普通对象的时候,看这里啊,嗯你看啊,我们如果不睡不启用偏向锁,也就是说不睡这五秒钟。
这时候我们new对象普通对象啊,注意看普通对象走,你,好一会把它给输出出来啊,that’s layout as essence to prinable s,把输入出来,记得结论就行了,啊。
这是咱们一个偏向所,没有启动的时候的一个普通对象,记住它长这样,下面呢我们来看偏向所启动之后的普通对象,让偏向组启动跑一下,比较一下,来比较一下,有什么区别,你看看这个对象上来。
是不是就自带着偏向锁的标记啊,101这里是什么零零有,对不对,也就是说当我们偏向锁机制没有启动的时候,我们这个对象啊就是一个普通对象,001呃,如果偏向锁机制已经启动了呢,它自带偏向锁标记好了。
这个对象就是匿名偏向,因为他上来呢还没有人给他上锁,还没有人还没有人锁他呢,也就是说他还没有偏向任何一个人呢啊,所以他叫匿名偏向,是这个意思,听懂了吧,很简单好,嗯关于这个图啊。
大概就是这样的一个小的升级的过程,我都讲清楚了,里面呢还有好多好多小小的细节呃,我都在那个笔记里头给大家记得比较清楚,vip里面会讲的比较详细,公开课呢我们就讲到这里好不好,还没上锁,咋偏向不是。
所以还没有偏向任何一个县城嘛,所以叫匿名匿名的吗,地名偏向意义是什么,没什么意义,就是上来之后呢,他已经把脑袋给你设设计好了,你不用再从普通对象转过来了,意义不大。
老师聊一下synchronized底层是怎么实现的,synchon底层我在笔记里给大家介绍的比较清楚,它本质上也是用log来实现,synchronized的底层是用log来实现的。
昨天我已经分享过了这个笔记的地址,找咱们任何一位小姐姐去找她要一下就ok啊,一我想现在呢我估计有一些那个大厂的面试题,你就应该能答得出来了,我瞅眼看看有哪些你能答得出来的,仔细从头读到尾。
这些都是百度阿里美团,什么顺丰,都是一些大厂的面试题,都会明天就送外卖嗯挺好,去美团送外卖,嗯在这儿呢再给大家拓展一些小小的细节啊,后面内容呢能跟上就跟,跟不上就算了,好不好。
嗯今天呢由于跟大家拓展的知识面比较宽,有一些呢其实大多数都是涉及到一些,计算机系的基本的这种基本的这种这种这种课,呃,这也是为什么,就是老师呢在这里给大家在我们的课程中呢,给大家设计好多这种基础课的。
原因就是基础课你搞定了之后呢,基础不牢,地动山摇,搞定之后呢,你就会走得比较高远啊,比较长久,基础打牢了,这里面有好多计算机系应该要玩的,一些基本的内容就是操作系统,计算机组成原理,io和网络。
计算机网络,然后那个linux系统算法,数据结构,今天听课的如果是有一些非计算机系的同学们,时间够的情况下,优先要把这部分内容搞定的,听懂了吗,补一点那个这部分内容的基本的基础啊。
今天今天是不是有人是那种非计算机系的有吗,有没有有的老师扣个一的,有应该有啊,因为咱们国内呢呃,搞编程的程序员其实很专业的并不多,当然他现在的要求会变得越来越专业,但是听不懂,你听老师的课就能听懂了。
你听我的课听不懂吗,我跟你讲这些原理,你听不懂吗,我们回到那个美团的面试题。
美团面试题呢,他就问你说那个一个对象,在内存之中的存储布局,那么各位同学啊,呃这里面其实有一个很好玩的地方,就是我讲的比较清楚,我说mark word是多大呢,是八个字节,对不对,指针类型是多大。
指针类型是四个字节,对不对,这就比较好玩了,各位同学,我不知道大家了不了解啊,就是你们的使用的虚拟机,它是多少位的,一般来说我们讲虚拟机这块呢,都是说你是多少位的虚拟机是吧,你是多少位的机器。
你们知道自己的虚拟机是多少位的虚拟机吗。
这块怎么查呀,挺好查的是吧,64位的对呃,怎么看呢,你敲一个命令就能看出来啊,看这里啊,我就敲java,这玩水就行了,这里写得非常清楚,64位虚拟机好嗯,你比方说你的操作系统。
你的windows是多少位的呀,64位的对吧,如果以前的话,实际上什么windows xp啊,还有32位的等等好,那么各位同学你们了不了解。
尤其是哪些非计算机系的,这个64位意味着什么,32位意味着什么,谁能告诉我这指的是什么东西什么的,什么东西的长度,什么东西的长度啊,寻址的宽度对啊,寻址的对没错啊,寻址呃,机器字长。
这跟机器字长应该关系不大啊,就寻指的宽度,指针的长度简单说就是指针的长度,就是我在里面一个指针,指针记录的是某一个东西的地址嘛,对不对,那记住这个地址的时候,这个长度到底是多少,这个长度呢64位的机器。
这个指针的长度就应该是64位,32位的机器,这个指针的长度就应该是32位,那么以前的xp呢大多数时候是32位,32位就意味着它的寻址空间,寻址空间呢,就是说我用多少个这么长的长度。
来标记我们整个内存地址,比如说我如果有一位,我就只能访问内存的两个小格,零或者一是吧,零或者一,如果两位呢,那我就能访问四个小格,对不对,01101100对吧,我标记四个地址,那如果是三位呢。
那就我能访问内存中的八个小格是吧,那如果是32位呢,那我就能访问二的32次方个小格好,如果每一个小格代表的是一个比特的话,我能访问多大的内存,二的32次方是多大的内存,各位兄弟,多大内存。
这个大家知道吗,了不了解,4g,所以,在原来的xp,你在这这种32位的xp的机器上,你装超过四个g内存,有没有用,有没有用,一点用都没有,因为再大的空间他已经访问不到了。
所以前的xp不知道有没有人还有印象,它最大内存就支持三个座机,因为它还有一些其他限制啊,识别不到对,那么现在的机器多数都是64位,唉你看我就知道有人64位,不就是八个g而已吗。
来各位同学有没有人嘲笑他一下,二的32次方是四个g,二的33次方是八个g,你自己给我算二的64次方到底是多少个g,我已经无语了啊,我买高科技,好好好,我们讲这个并不是为了给大家讲讲内存啊,主要看这里啊。
就是我们java虚拟机啊,现在是64位虚拟机,64位虚拟机,它的内部的指针长度应该是多少,是64位,各位同学,64位,可是我们刚才所看到的任何的对象啊。
刚才我在给大家演示这个对象大小的时候,大家都看到了我们看到的任何的对象,它的指针,我们说这个指针这个指针是多少四个字节呀,这就开玩笑呢,您您您老人家64位的机器,结果你弄一指针出来四个字节。
这是以前有面试官问过的,why,这四个字节四个byt,为什么好,各位同学,这里是压缩过的啊,这点你要知道这是压缩过的,还有我讲过,我说在t里面,我们看这里啊,没有,我们还是用这个t啊。
三回头来给大家补一点,这些基础知识,因为如果真的问到这里,其实就能问出来你到底是计算机系的,还不还是不是计算机系的,我就这么跟你说啊,作为面试官来讲呢,他判断你到底是计算机专业还还是不是。
就问你这些基础知识啊,t小t等于net,我们说如果t里面有一个string s,各位同学它的长度是多少,按理来讲,您老人家是64位的机器,是不是64位的,加入虚拟机,你这个长度必须得是64位。
八个字节才对,你说对不对啊,同学们,可实际上实际当中是什么样子的呢,跑一下看,它是多少个字节,四个字节看了吗,它的指针是多长,他这个脑袋上这个指针是多长,指向那个class的指针还是四个字节。
ok这玩意儿就就有点有点过分了。
原因是什么呀,原因是你需要理解java里面有一些好玩的参数,我们把这些参数让你给他展现出来,java conversion,要么更,print come on lying flags。
老师的记忆力还可以啊,princeline flags,就是把那个命令行参数自带的那些,全给自己敲出来了。
conversion,大家看这里,这里头呢有一些这是java自带的参数,看了吗,concurrengc threads,这就是有多少个gc的线程是吧,一起就11个啊,所以说我们讲这版本启动的时候。
有好多好多个线程启动,这里面我们主要看这两个参数,这里我们用的是g y g c k,我们主要看这个参数,这是其中的一个,这是其中的另外一个这两个参数啊,这两个参数呢就是去。
就是决定着你到底是压缩了还是没压缩在这里,这是它默认的参数,呃这边调优课呢,主要讲这些参数怎么来进行运用,什么意思啊,读一下,理解一下,compressed as sponders compress。
压缩的class pointers类指针类指针进行了压缩。
所以我们这里看到的,我们这里,这里看到的这个指针,这个指针它就是四个字节,因为它开启了压缩,那么后面这个是什么意思啊,o p s的全称呢叫,ordinary。
ordinary object pointers,好就不写全了啊,普通对象指针,ordinary object pointers,就是普通对象的指针,什么指针,这个指针这个指针它也是压缩了。
还有同学说老师我能够打开它这种压缩吗,打开压缩呢有两种方式,第一个呢你的内存足够大,就是你使用的内存足够大,你这外面使用内存一般来讲,超过32g压缩就不起作用了,如果你jvm管理的内存超过32g。
压缩自动不起作用,各位听懂了吧,这是第一个一个结论,第二个呢我们可以使用参数来把它打开,我们来看一看参数打开的状态好不好嗯,到现在还能跟上吗,各位兄弟们能跟上老师扣个一来。
就后续我真心希望你们扎扎实实的跟着老师,第一好好训练训练基础,第二呢顺带着把java虚拟机怎么优化,各方面的内容也都掌握住,多线程内容掌握住,这样的话呢,最起码很多很多的那种基础型的大大厂的面试。
你就能搞定了啊,我们我们跑一下这个还是这个小程序啊,我们跑下一下run,我们指定它一下,just test edit,指定他的vr motions program arguments o。
指定他的vm options on gram xx,加号就表示开启,减号呢就表示关闭,等着我们关闭掉,use嗯,impress o o p s,就是我们把那个普通对象指针给它关闭掉好吧。
apply run,跑一下,看,好各位同学仔细看,现在我们这个,我们这个普通对象的指针s变成了什么,自己看变成什么东西了,o,八个字节是不是啊,同学们好,大家看到了吗,看懂了吧。
嗯当然我们可以把这个也打开,这个时候呢我们这个指针就变成了八个啊,这是,一些小小的基础补充给大家听啊,运行的时候再解压缩,是的是的嗯,好这块内容大家听懂的,跟得上的,给老师扣一,下。
面我再问你一个触及灵魂的问题,一个触及灵魂的,涉及到计算机基础知识的问题,这个呢比较难答,我想问你的是,这个压缩的时候是把八个字节压成四个字节,按理说这四个字节它最大能够管理的内存,我再说一遍。
一个四个字节的指针最大管理内存是多大4g,可是我刚才明确说过,jvm什么时候这种压缩它会失效,超过32g才会失效,那这事儿就很神奇了,一个压缩完成之后,只有4g能管理四个g的这么多的地址的。
这样的一个指针,他居然管理着32g内存的,是y y32 g内存之前他都可以用压缩的啊,这个你们自己去实验就知道了,这儿曾经有一个忘了某一个厂子的面试官,问的啊,物质是由原子构成。
现实只允许操作到分子水平ab 8哈哈,虚拟定位说的很对啊,就是说说的很对,说的很对,没错啊,这其实呃这两位同学他都是明白的,说的是对的,仔细听这个很简单,就是说在java里面操作任何的数据的。
基本单位是一字节,一个字节,也就是八个八个位,有时候我一个地址啊,我不4g一个地址吗,二的32次方4g个地址,我一个地址啊,代表着是一个字节,而不是一位听懂了吧,所以这里头呢是4g乘八,一共是32g。
32g内存,32g内存之后压缩才失效,ok,好讲到这里,其实还有一点扩充的知识也可以补充给大家,这块儿大家还能跟上吗,能跟上,我就稍微的扩充一点点好不好,对一些基础稍微好的同学,我扩充一点点啊。
不能跟上就算了,给老师扣个一来,我们看要不要再再再再扩一点,ok好看看多少啊,00976还在听呢,jack夏天铜墙铁壁,这些都是变变变得很久的人,好小柳马上马上成功,大家可能了解就是一个jvm的虚拟机。
它的垃圾回收器呢有好多种是吧,垃圾回收器呢原始的有那个serial serial两种是吧,serial serial,young serial old就年轻代老年代有两种。
两种cereal两种parallel两种并行的,这单线程的是多线程的是吧,然后c m s和他加那个po啊,这两个配合的是吧,这是六种,一共是六种了,这是两种这两种这两种,那么背后呃。
现在我们用的比较多的是g one,叫gabbage,first k g one,那么g one之后呢,我们又又有又有两个是吧,这这两个分别叫叫什么名字,大家知道吗,叫shannon da,谁能懂。
这东西是一个那个美国一个公园的名字啊,还有一个呢叫zgc,这个呢是下一代的垃圾回收器jdc好,还有一个是什么,还有一个是appellent,这东西是用来做测试用的啊,这个用的很少,大概一共有十种。
在这时钟里面呢,下一代的垃圾回收器,就是它z dc效果效率非常非常高,高的原因在哪里,他在指针上做文章,大家知道64位的指针,它可以寻址的空间极大极大,实际上是用不完的。
后来呢整个jdc是在64位指针的基础之上,一共用到了48位,在启动在这个基础之上叫颜色指针技术,叫color red pointer,color red pointers设计了非常漂亮的垃圾回收器啊。
这个垃圾回收器呢color pointers 64位的这种指针,其中用到了其中的四位o很好玩,总共用到了48位,实际上没有用用用特别多啊,如果大家会有兴趣,可以去钻研一下。
向面试官展示你知识面的宽度深度,以及你对技术的好奇心,好吧,cdc会大面积普及吗,我这边m调优不是白学了,在你普在大面积普及那一天,你也没有白学,好多时候你能讲出原理来,讲出历史来。
在面试官的印象要比别的人要深得多,大家可以去研究一下那个color pointers,那里面又牵扯了很多底层的这样的技术,挺好玩的嗯,细节我就不展开了,因为这块的话呢,估计大多数人是不了解这方面知识。
以后都用这个k 11了嘛,这无所谓,看你们用什么,好那个我今天的技术内容我就聊到这里好吧,昨天呢我也给大家介绍过咱们自己的课程,咱们课程呢还是那句话,是从零基础开始,从零开始一直到百万年薪的水平。
在一两门课里有所体现,一门课呢是入门,就是整个课程的,其中有门课是入门,就是java后端工程师啊,这里面呢适合小白,刚刚入门的同学入行,这里面是最大值,在里面集合里面我可以给你调最小值。
这样的入行的话呢,你会非常非常的快啊,快速而明确,在入行之后的提升呢是另外一门课,这门课呢叫架构师呃,在这个教育师课里头呢,整个内容呢大概100多门课程啊,我们教这100多门课的时候。
也并这是一个最大值啊,还是那句话,我提供给大家的是最大值呃,真正你学习的时候呢,可以先挑最小值来学,再慢慢进行体系化学习,这是我所提倡的,先赚了钱,涨了心,跳了槽进了大厂,然后呢。
在真正的慢慢的跟老师进行体系化的训练,你这时候你会发现,你后面的职业生涯会越走越好,越走越强,这个这个学习路线呀,这个学习路线呀我也给大家展示过啊,崭新的学习路线是吧,这也是比较全面的学习路线啊。
你像在这里面的话,老师给你画好路线之后呢,你就可以挨着牌的一条路线,一条路线的一门课。
一门课的跟着往前走啊,操作系统是吧。
你像,呃这样的话呢就会能做到,咱们的学习效率比较高,高到什么程度呢,绝大多数的同学寻求涨薪的,三个月之内就搞定了,寻求入行的3~6个月业余时间就搞定了啊,如果你要想快速入行的全身心投入的话。
有可能是两三个月就搞定了,这就看你每天投入的时间,因此呢不要看咱们课程多,课程多呢给大家的素材多,但并不意味着你要把所有东西一口气全学完,一口一口吃台阶儿,我们一个一个卖,慢慢的。
我们迈向薪水比较高的那个台阶上去就行了,vip课呢目前有直播和录播两个部分构成,我们直播完成的东西,它就一定会形成录播课,我们直播的内容,大家也可以在咱们的网站上直接查询呃,直播课呢向大家负责任的讲啊。
后面由于是那个端午节,所以这个呢今这周的直播课会相对偏少,但是你看上周的直播课,你就会发现咱们直播课的内容超级多,那个我们直播课的内容大概相当于其他机构的,至少是三倍以上,直播课完成之后会形成录播。
避免有同学你错过之后呢,唉没有办法再继续学习这个意思,所以是直播加录播嗯,这是咱们整体的课程的量以及课程的特点,定制化呢是咱们最大的课程特点啊,呃因为这样的话就能实现每个人的情况不一样。
那么他的学习路线就完全可以做到不一样,他的学习效率就和其他人比较高很多,如果你在线下学习,咱们内容全是一样的,我学这个,我明天讲这个,你听不了,别的线上不一样,我想让你听哪一块,你可以优先听哪一块。
这是线上所带来的好处,而且在我们大量的素材的前提之下,我可以帮你定制各种各样的快速的路线出来呃,在这里呢在咱们的整个细胞里呢,大家自己去可以也可以去了解一下,绝大多数同学啊,三个月搞定快的话。
学了半个月涨薪10%,10%,虽然不多,在疫情的情况下学了半个月而已,也还可以吧,俩月原公司涨薪4k一年5万多也还可以吧,这是学的时间比较长的,十个月薪资从10k涨到17k,1年涨了8万多。
这是学了俩月12k offer继续提升,刚入行的应该是,这是毕业半年让他涨薪涨了50%,这是花旗和微软的两个offer,这是面面试突击的课,跟着咱们学完,年薪涨了6万啊,整个课程内容的话呢。
从咱们入行开始,到很多人不愿意讲的这种底,非常底层的基础的内容啊,好多机构其实不愿意讲这块,因为它很枯燥,但是它又很重要,它是我们的易筋经,是我们基础中的基础,尤其是关于算法这块,关于算法这块。
这是这只是入入门级别的整个算法的内容啊,在咱们整个课程体系里面也是很大的一块,那个算法这块呢是咱们嗯左成云,左老师啊,大概呢讲了九个阶段,不能这没有点开啊啊,小姐姐们帮我反馈给咱们的技术,这块没有点开。
我不知道是什么情况,我我直接反馈吧,反馈一下,诶老师你看一眼那个数据结构和算法,那个大纲那里面的那个图片是点不开的啊,阶段一阶段二,看一眼,看一眼技术那个是怎么是怎么回事,呃算法内容是咱们的重中之重。
这里面大概包含了新手班的学习体,系班的学习,然后刷题班的学习面,常见的面试题呃,精品这种高频的面试题啊,算法的押题的内容基本上呢,每周啊基本上都在更新,这是咱们正在更新中的是吧,4月第四周嗯。
5月第一周,ok这些都在更新之中,好,呃有了这些内容呢,就是底层基础你会打的比较牢靠,当然了,还是那句话,就是说在你时间不足的情况下,你也可以先补补这些知识啊,老师可以帮你找到一条。
比较快速的升职涨薪的路线,然后升值展现完之后呢,再慢慢的进行你的基础化的训练,今天讲的很多内容呢,是来源于咱们并发编程的部分啊,大家打开大纲自己去进行查询,rpc的通信原理主要讲jk double。
然后消息中间件我们主要讲rocket卡夫卡,poser rabbit,active缓存的中间件呢我们知道叫memory catch和redis,软件设计的基础,u ml设计模式,软件工程的发展。
高并发相关的分布式的架构的实践,高并发高可用的部分啊,e t c d h a proxy key lives zk,通信和调用呢我们主要讲这个restful thrift,nt double。
缓存中间件主要讲redis存储中间件比较多啊,fs dfs,ht,fs mango,tedb neil否认ob click hospute等等呃,分布式锁各种实验方式,分布式事务,各种实验方式。
链路追踪的实验方式主要是step walking,预警监控,普罗普罗是吧啊,ok其他的各种分布式的东西,这个完成之后,我们主要来聊回复,两大体系,微服耐飞微服,阿里巴巴啊,这个完成之后呢。
我们主要来聊系统的性能优化,这是你简历中呃增光添彩的一方面,jvm调优,mysql调优,tomcat调优,alex调优是吧,高并发大流量的服务的调优的实战案例化,海量数据的处理存储搜索。
我们对于大数据这部分啊,e l k cloudoris啊,new ycle had to flink,这些网络基础设施建设运维层面,我们主要讲dns相关,cdn相关啊,全球同服的问题啊。
多级缓存资源静态化落地的问题,服务保障device,现在我们开发开发之中,所应用的最多的开发模型,软件测试的部分赠送大家一期一期课啊,only one service mesh呃。
如果你用go语service mesh是经常使用的,用来实现微服务的方式好了,这块呢就是咱们整个的基础点的内容,搞好技术点之后呢,要学会下一步的设计过程,指挥技术点,不会设计不行,好去聊理论基础。
去聊基础算法,去聊原理和源码的剖析,这块是你跨越落地奔向设计的要跨越的一,一站在这个基础之上,学习设计理论,高性能的架构,怎么设计分流,怎么设计并行并发,怎么设计缓存,存储可靠性,怎么设计。
应用保护怎么设计,在这个基础之上,再用各种各样的案例来帮你做实践,电商秒杀怎么设定红包,怎么设计微博互关百万级的并发,这种票务的联网系统,12306怎么设计弹幕系统,全链路压测的方案的设计。
零零丢失保护方案的设计啊,大数据相关的各种设计专题等等等等,最后我们用亿级流量这样一个完整的项目,来让大家完成一个比较完善的互联网,三高级别的架构师设计啊,这两个完成之后呢,基本技术方面你就搞定了。
好吧呃我不能说到头了,但也差不多了,在这些基础的基础之上呢,我们去学习云原生相关的啊,这是我们未来架构的重中之重啊,现在呢全球来说就是不管是大中小,各种各样的厂子都在上学,原上没有不上云原生啊。
从各种各样的那个软件及服务是吧,基础设施及服务平台及服务等等,一直到后端及服务啊,b a s云基础云架构容器容器的编排监控,devops持续集成,core sphere。
easter terrifensable,公有云,私有云到混沌工程呃,这种东西呢可以这么说,在中小的那种城市里面,二三线城市里面,你可以吊打很多人还掌握不了呢,常见的半个处理专题。
这东西呢主要是提升你们面试的时候的这种嗯,技术水平,说出来的内容比较高大上,薪资会比较高,那么从技术角度再往上就是要进行团队管理了,咱们的皮班老师,他是原来的真正的p8 管,100多人的。
教你怎么进行大型团队管理,咱们的p9 老师,原来是管理200多人的p9 团队,ok教你怎么运用产品管理好吧,ai送大家一个入门,这样大家做一个入门,ok中台的构建领域驱动d d d带大家学习好。
学习好啊,好整个技术的体系我就介绍完了,除了技术体系之外呢,我们另外的就是项目体系,项目体系就不一一介绍了啊,就是咱们可以写在简历中的项目非常多,解决大家伙你简历中项目没得写的问题,两大项目介绍给大家。
第一个呢是咱们飞机出行新版的2022,从项目的介绍,组织方式,整体设计开发规范,整体的技术栈的选型,到用户端到api的服务层,到service的服务层啊,各种各样的服务,健全订单消息网关地图等等派单。
然后到项目怎么测试,到项目怎么部署,怎么扩展,再教你项目怎么怎么拿这个项目去面试,如果以前只有c r o d传统项目的,搞定一个飞机出行,互联网级别的高并发的项目,你就有经验了,那么第二个呢。
是我们自己现在正在对外运行中的,你可以直接下单的啊。
咱们的马士英严选,在咱们的严选的里面呢,又是一个大概老是投入了呃,不到30个人吧,前后啊,前后不到30个人,为大家研发了这种大型项目架构,这这这个课是一个真正的呃,开发出来也在实际当中运行啊。
你也可以了解咱们整个后台架构,也可以在里面下单的真正的一个项目,也有咱们的pc端,也有咱们的h5 端等等,严选的商,这个咱们严选商城来讲的话呢,内容呢牵扯内容会更多一些啊,有各种各样的内容会更多一些。
我建议大家要过去,因为你会读到一个完整的稍微大型一点的项目,它到底具备哪,是哪些团队来做的,是由哪些技术选项,要选的是由哪些架构要构建的,从前端架构到后端架构,到运维架构,到各种中台的设计。
到应用架构的设计原则,容容量怎么估算,服务怎么设计各种的服务,然后到中台怎么设计到测试,怎么样进行自动化的测试,怎么性生成报告,怎么进行微服务的治理,怎么进行链路的追踪,怎么进行可视化的监控。
怎么进行容器的管理,好吧,怎么进行多租户的管理,包括我们开发的整个过程,开发运维的一体化是怎么实施的,ok呃我们搜索的过程ef k是怎么完成的,项目的规范是什么样子的,呃读完这个白皮书呢。
你可以自己带一个小团队尝试,就可以自己带小团队了,ok至少能你读完之后呢,别人问你,你说你们项目有多少人,你在里面做哪个哪个哪哪哪个东西,你能够完完整的说得出来啊,这是咱们的一些技术的选型啊,前端的。
后端的,pc端的h5 端的后台管理的,后端的架构的嗯,水同步用什么配中心,用什么网络用什么,然后这个是咱们后端后台的那个整体的运维架,构长什么样,这是咱们自己进行的飞马系统的框架设计,可以用。
大家也可以直接拿去用,我们也是准备开源的,这是咱们后面的架构的设计是怎么做的啊,这是咱们中台的设计,这是咱们i m的中台,这个是支持上亿级的那种并发的i m啊,它不是一个很小的就简单的聊天系统啊。
那个是拿不拿不出手的啊,这是咱们支付中台是怎么设计的,ok搜索中台怎么做呃,很具备参考性,各位同学可以拿去直接应用。
在你们现实现实项目里,我们直接把它放到网上。
你们下单也好,或者是学习也好,都可以拿来用好吧,ok,整个大概的这个内容的介绍就介绍到这里啊,最近呢咱们在搞我们的报名活动,典,报名的同学呢可以享受咱们的抽奖,一等奖是苹果板,二等奖是iphone。
三等奖是pad,四等奖是无人机啊,五等奖是曼卡顿音响,那么,整个课程呢呃还能享受的其他的一些优惠,呃,我觉得一门好课,给你带来的是你的整个职业生涯的颠覆式的,你收到的收获和收益啊,这个是很大的啊。
各位同学可以从咱们的就业里面,能够找得到这其中的蛛丝马迹,这里面呢没有任何一个聊天记录是给你p过的,只是隐藏了一些隐私信息,没有任何一个聊天记录是假的,好吧,你像,三个月入职涨薪70%就学了仨月。
一般情况下想涨薪的话,三个月足够啊,除非你水平特别差好吧,可以优惠几千吗,问咱们小姐姐吧,ok,现在有的公司是不是都拆中台了,有的是这样,但中台这个概念呢,其实你也不要把它想象成是一个。
你可以理解为我们中间的一层api层啊,你不要把它完全理解为说,马云原来提出的这种中台概念,那个是好多人都拆了啊。
这是应届生嗯,欧克原料14x18。
呃各个层面跟咱们学的同学,其实最后都得到了他们想要的结果,干哪种类型的项目对自己提升比较大,马士英严选这个项目要要完白皮书,你就知道了,你把它搞完,上上次有一个同学就是说搞完这个项目啊。
他突然间发现了他所有的全通了,就是所有知识全通了,你能理解这意思吗,如果我们平时学的某一个点啊,redis卡夫卡啊,spring spring mvc,什么mysql等等,这些都是一个零件的话。
你会发现咱们严品项目把这些零件全穿起来了,穿起来了之后呢,你会有那种感觉啊,就是有那种一体化的感觉,整个知识体系全建立了,然后再去看这些知识点的时候也就比较通透了,所以呢项目驱动很好的学习方式啊。
推荐大家使用,我咨询小姐天天睡到下午才起床,回信息,因为咱们咨询小姐姐,每天晚上12点之后才下班,所以咱们是下午上班,这个是哪位小姐姐,你可以再找她一下,你专门在这里,我专门跟她说一下好不好嗯。
最晚报名,明天抽奖,明天晚上是咱们抽奖的最后一天,明天晚上咱们周年庆典的活动就结束了,大家对于技术也好啊,我仅仅讲到了各种各样的技术,或者对于工作形势前途,职业发展课程有任何问题的,我们聊会儿聊天儿啊。
咱们准备11点吧,好吧嗯,物联网是不是不怎么好,不是不怎么好啊,就物联网呢他也是一个很大的行业方向,它里面的需求的人也挺多的,嗯物联网的多数是跟那个什么有关系呢,嵌入式跟这个关系比较大。
呃他的薪资呢确实不会像互联网后端这样高,他是这个意思啊,但是也谈不上说不怎么好,所以你得定一下,你这个不怎么好是什么意思啊,没有什么不怎么好的,挺好的啊,我们前20名报名的同学呢有500的返现。
有咱们白金的vip卡,这我稍微介绍一下啊,就是说有这张卡的好处呢,在于咱们后面的升级的内容,ok你可以用很小的代价就可以听,呃,你像我们目前每年升级的内容,目前每年的升级的内容呢大概是几百个小时吧。
几百个小时后面还会多啊,还有好多好多其他的内容啊,文字的内容,音频的内容,视频的内容都会有,像刚才给大家看到的直播啊,或者说咱们的科研更新,你在这里都能看到,就是说我们有哪些更新计划,什么时间再更新。
什么时间再更新,哪些的更新都在这里写的非常清楚,就是咱们更新的内容呢,有了张白金的vip卡,你只需要付一个流量费就可以听了,什么叫流量费呢,大家都知道啊,就是我们现在对外提供的这个平台,我不知道大家。
你很多人学习课程是在咱们手机上,手机上下载咱们的这个,app啊,这是咱们app,你下载完成之后呢,直接打开点开课程就可以学,比如这个鸿蒙鸿蒙的基础课,鸿蒙克是吧,嗯打开来。
再看这里你直接就可以进行学习啊,那么这个里面呢是我们要付给那个嗯云厂商呢,呃流量的费用啊,我我希望你每年负担一个流量的费用,老师呢就可以把课程免费的送给您,能理解的意思吗,就是咱们更新的内容啊。
你付一个100多块钱的流量费就够了,1年,马老师,请问张一鸣老师为啥不讲了,您得问张老师去啊,张老师有他的想法嗯,老师鸿蒙有前景吗,我认为有前景,但这东西呃预测未来是有风险的啊,我比较我喜欢啊。
我喜欢鸿蒙挺好的,因为当你到达某个层次之后,你会发现所有的东西,所有的脖子都在别的国家的手里头掐着你,你会非常非常非常的难受,我告诉你啊,我觉得任何一个系统,哪怕他现在不是很成熟,不是很好。
只要能够愿意打破这种垄断,我就喜欢去推广它,所以很多那种培训机构没有的课,这里有一堆,主要是咱们老师的一些情怀,那个从mc体育课里面我就能看出来一些啊,就说有一些课呢,你可能听都没听说过的。
比方说我刚才跟你讲过java语言和go语言的区别,他者的区别呢,是携程,但是java里面有没有携程的解决方案,当然有java里面携程的解决方案,colin的自带那个kim,阿里就用过用它来做解决方案。
这是我专门请的,阿里用kim做过解决方案的老师讲给你讲的,其实从这你就能看出来,就是老师选课的时候,一个就选老师也好,选课的时候一个讲讲究的程度,我毫不夸张的说,很大多数机构做不到这一点。
因为呢我我我是能够动洞洞察到,就是说我们需要哪些东西,你有可能会需要将来流行的地方,到底是有哪些提前的,就帮你把内容准备好了,kim是阿里的,这个以前用携程去做一些高并发处理的时候,使用过的解决方案。
好吧,这里面也有携程,你像整个mc里面,我们为什么要讲go浪,各位同学就mc叫架构师,架构师实际上是跨越语言的,后面呢我是想把整个架构师的呢,慢慢的升级成为java加go双语架构时。
这些个升级对于咱们现有的报名的同学来说,是免费的啊,当然我们真正升级完成之后,我们整体的课程价格是一定要往上调,一调的内容变得越来越多了嘛,嗯呃也就你也就不用再纠结了,我是走java还是走够了,没关系。
我一个课里都给你包含了啊,你选哪个,看你实际当中需要哪个,ok这个还可以吧,觉得还可以的,老师扣个一来认可一下是吧,打个牛逼出来啊,双语架构师啊,我们准备要退出了,也就嗯。
计算机语言一点不懂内容来学java吗,你原来所有人都是从不懂过来的啊,没学历寸步难行,没学历补学历啊,你学历差到什么程度,中专初中大专感觉白扯了,大专是绝对够的学历啊。
但是我个人虽然我个人提倡你还是要补到本科,但是大专学历,在很多时候呢,其实是已经非常非常的完全够了的,这是菲律宾从大专那边转成java的,涨了7k还,这是大专二线城市薪资直接翻番了。
这是大专,武汉四个月涨了7k一对啊,19年大专毕业生跳槽,直接涨了5k大专的应届毕业生,直接让他拿了21k能想象吗,这就是咱们的课程啊,非全大专一样的啊,这个大专本质上都差不多啊,就是不是非全没有关系。
你既然学了非全大专,我就建议你再补一个非全本科,听懂了吗,大专你好一点的,甲方费劲,这个呢是你的技术不行,不要怪学历,给咱们讲那个bug课的就是一大专生,他原来在京东,现在新浪,你跟我说费劲。
只能说是你技术不行,java python都学时间够吗,没必要都选一个架构师呢,了解语言的特点,带领下面的团队就足够了,没有必要把所有细节全掌握,逍遥说专升本没有学位证,大厂可以进吗。
本身这个是这怎么说呢,就是说你有些大厂是不在乎的啊,但是说你的技术得特别特别大的,比比其他人强才行,就是我一个很粗浅的例子,一个是大专生,一个是本科生,如果你们俩的水平是一样的,那我一定选本科。
比如说你的这个水平,一定要高于这个本科生的水平,你才有自己的竞争力,能听懂吗,所以付出自己的努力啊,有有一些大厂是并不在乎你的学历的啊,比较典型的京东阿里都不是很在乎你的技术,非常到位的情况下就可以。
厉害想知道他们的成长经历,这是逆袭,没有什么成长经历,跟着我们学课程,把基础锻炼好了就成了呀,你搞技术的,你只要把技术锻炼好不就完事儿了吗,嗯阿里学历差的别人不行吗,听不懂你在说啥。
我有好几个学生专科实践的案例,但是筛选简历根本不行吧,除非内推,我们所有的国内的一线大厂都有内推,前提,你得水平够,你不要跟我说,那我水平不够啊,我又是专科,你就得给我内推,那不扯淡吗,所以呢学历不行。
技术来凑啊,赶紧你,你如果学历不行,技术又不行,我不知道你的长处在哪里,别人为什么要看好你,多大岁数就不建议学,一般我是建议32岁,如果你还没有入行,就不建议入行,不一定对啊,这个只是个人的一个看法。
只是我现在补了本科挺好的呀,补上,我们明天明晚就抽奖了啊,今天晚上可以说报名的最后一个晚上了,大家走过路过,不要错过我们这次最大的活动,这次活动一定是他的力度,是超过咱们618的啊。
这个是给你一个承诺啊,不会比618的活动的力度更低啊,不会有科大讯飞那推岗吗,还真有啊,这个由咱们的严老师直接可以给你推进去,杨老师,原来科大讯飞出来的,他选妃本身不是个特别嗯特别牛的场子。
系列 6:P36:程序中最难调试的BUG:野指针和并发问题 - 马士兵学堂 - BV1RY4y1Q7DL
我告诉你程序之中最难调试的bug就来源于这里,程序之中最难调试的bug,一个是野指针,一个是并发问题,这两大问题是程序之中最最难以调试的bug,好解释一下什么叫野指针,野指针的意思是很简单。
同一个对象释放了两次,好这是什么意思,不能说呃,sorry,不能说,释放了两次,就是同一个对象,同一个对象,两个指针一个释放了,另外一个不知道还拿来用,或者说虽然是同一个对象,是是可能是同一个指针。
或者说是同一个指针,不同位置,其中一个七这个对象已经释放了,但是另外一个指针的另外一个位置的指针,不知道,另外一个线程里面的指针不知道好,它依然还在使用,这个是野指针,就是不再指向任何对象的指针。
这就是著名的有一个异常叫now pointer exception,呃如果你原来学过c语言,c加加语言,经常的这种东西会引起内存的崩溃,我告诉你,这是所有语言所面临的最难调试的bug。
包括java这个东西是怎么产生的呢,非常简单,给大家看看这张图,所以大家再稍微画一下,大家看这里简化一下,同学们听我说,呃,我不管你是任何的语言,假如说我们有两个指针,ctrl c trl v。
要o了要p吧,好看这里假如这个o和这个p这俩哥们呢,同时指向的是同一个对象,那么如果我们程序执行的时候,比方说我在main方法里面要把这个对象给干掉了,或者我在m方法里面把这个对象给干掉了,给他删了。
那我问你main方面的这个小o,它指向的是个什么东西啊,指向的是什么东西,java叫地址,没有指针,java叫引用,本质上就是指针,好吧,我们谈本质啊,不要谈那个那个那个你你不要咬文嚼字。
你不要学孔乙己,非得跟我矫情,回字有四种写法,这个东西没意义,理解什么意思就行好吧,玩文字游戏是最没劲的,嗯这就是这时候就变成空值了,对不对,更有甚者,你这块删了之后被别人给占了,你想想看会发生什么。
会发生,你指向了别人的对象,也许你操纵,我告诉你,你拿到了别人的这块内存里面的东西,以前啊在内存里面偷别人密码,就是这么干的,嗯好听,我说这是程序史上最难调试的bug,就是野指针。
这个指针指向了它不该指向的东西,他特别严,这个这个就叫野指针,不知道我说清楚没有,c和c加加里面呢是永远你要面临这个问题的,也许一不小心你这边删了另外一个指针,还在使用它。
也许你这不小心这边删了其他的程序,或者说其他的程序的部分内容,又又又又占用了这块空间了,那么这时候你另外一个指针指向了它,不该指向的内容,好了,我现在并没有聊java语言,我现在聊的是所有语言。
就是无论是什么什么语言,都要面临这个问题,你要正确的删除这块空间,不能多删一次,也不能不删,还得保证你删完之后,所有人都用不了,好吧,这是非常非常难的啊,我告诉你,这是第,这是第一种特别难调试的bug。
历史上这种bug呢维护起来超级超级难,你知道go语言是怎么诞生的,go语言是原来google为了替代他们以前写过的好多,c语言的程序,c语言程序写起来也许比较容易,但是维护起来超级麻烦。
bug调试起来特别特别困难,所以他们开发了go语言,go语言呢,不再用手工的方式去维护这些内存空间,而是调也跟java一样啊,引入了gc,当然这是最难调试的bug之一。
那么第二个最难调试的bug是并发问题,我觉得这个问题稍微一说你就明白,就是多线程,访问同一块儿,内存空间,如果这个并发问题,再加上野指针问题结合起来的话,你调试起来就更麻烦了,这里只是一个县城站。
完全有可能我还要来,另外,另外的一两个这个是非常有可能的,你想想看,行了,这图不太好画啊,这这图呢不太好画,缩小一点,这哥们放这边来,完全有可能发生一种什么情况,我这个县城站里面啊,也有好多好多的指针。
好,我指向了这个对象,也许是我这个线程把这对象给删了,也许是我这个线程访问的时候,我俩同时开始写,造成了数据的不一致,好了,我告诉你,像这样的问题,调试起来是最最头疼最麻烦的。
不知道大家有没有这方面的体会,当然有同学说老师我天天写cr o d,我是没有这方面体会的,那就没招了,这也是为什么你呃,你你你你你你,你不应该不能只关注c r u d的原因,因为面试里面好多好多的问题。
都要牵扯到这方面问题了,好吧,嗯所以所有的程序啊,最难调试的bug基本上就这两个,这是最难调试,一个叫野指针。
系列 6:P37:站在巨人的肩膀上:且看语言的发展史 - 马士兵学堂 - BV1RY4y1Q7DL
可以这么说,在最开始的语言的发展的历史上,都是沿着对这种bug来来来,更加容易调试的这个方向不断发展,像原来c和c加加的话,大家应该知道这种是什么事实,怎么怎么管理这块内存啊,怎么管理这个指针的呀。
叫手工吧,手工管理,不知道有多少同学是学过c或者是c加加的,有没有有的话,老师扣个一来cba里面分怎么分配一块内存,a memory allocation对吧,当然他有好多好多函数都可以分配啊。
这其中一个reallocation的意思,我就是开始诶,在我们的内存空间里面找了块内存,但是你总得释放它呀,你怎么释放free这个函数就可以把它给释放了,但是我告诉你啊。
也许因为程序里面充满了各种各样的分支,循环啊,各种各样的不同的岔路,它并不是说只有一条路线,所以只有一条路线的话就简单了,我这边分呃memory allocation完了之后呢。
后面马上就把它free掉,可是在很多情况下,我是需要判断的,在这种情况下我要把它删掉,在另外一种情况下,我不要把它删掉,我告诉你,这就造成了各种各样各种各样麻烦的bug,所以手工管理内存。
无论是c里面的memory allocation,或者是c加加里面的new和delete,本质上他这这这哥俩是一回事儿,这两段是一回事儿,都是需要你进行手工管理。
手工管理最麻烦的事情就是你不小心忘了删了,你知道吧,这空间你分配好了,但是你不小心给忘了,你把它给忘了,忘在这了,这时候会会产生什么,告诉我一下,忘记删除,忘记释放,这个呢叫memory lake。
这叫内存泄露,不要不要叫内存溢出,大哥他没有溢出,它只是泄露了,泄露是什么概念,泄露的意思就是这块空间呢虽然说留在这里,但是所有任何其他的程序不能去访问它了,不能使用它,他留在这儿,他没用了。
但是别人也不能用,这就叫泄露了,如果泄露越来越多,会发生什么,泄露的越来越多,泄露越来越多,会发生一种现象,就是当新的内存空间要申请的时候来了,我需要申请这么大一块。
我突然间发现这里面充满了一个一个洞一个洞,而且中间我找不到一块连续的内存,来为我这块内存分配空间了,完蛋这个叫内存溢出,泄露过多的时候容易产生内存溢出,但它本身不叫内存溢出,保存memory。
当然这种的还算是不是不是很严重啊,大不了我重启一下是吧,你又能跑好长好长时间,所以调优jvm调优最重要的一点叫做重启,每两周重启一次,玩过游戏吗,有的游戏是不是就这样,各位指挥官。
我们的游戏服务器将在五分钟之后启动,进行维护,在此期间不得互相攻击,good,你们已经学会了第一种调优的常用的方式,当然你不能跟面试官这么说,做过调优吗,做过怎么做的,重启面试官一个大嘴巴子给你抽上来。
哪凉快哪呆着去,这是第一种有可能会产生问题的地方,叫旺季是吧,第二种是什么,第二种叫做,释放多次就是你释放了一次,你delete了他的一次,由于有分支判断各种各方面的情况存在。
也许有可能你free了好多次,delete了好多次,这个有同学说没问题啊,这块空间我不是干掉他一次,没关系啊,我再干他一次吗,不就是尸体让我又干了他一次吗,鞭尸而已,没错你只是编了个诗的。
问题倒是不是特别大,但关键是当你干掉他第一次的时候,有另外一个人已经把这块空间给重用了,人家已经又放上有用的空间了,结果呢,你第二次回来又把人这个有用的数据给干掉了,结果另外一个线程就会发现莫名其妙的。
你发现没有,莫名其妙的,你的数据就没了,所以这是为什么说我们多线程这种bug,特别难调的,原因就在这里,你的线程好好的没bug,你懂吗,甚至说你的进程啊,如果是进程之间共享的话,你的进程没bug。
没有毛病,你的程序也没有半毛钱毛病,可是很不幸的是,由于有别人家写的bug的存在,他会很容易的把你占有的这块空间给你干掉,你找谁说理去,好了,这个叫释放多次,产生,极其难以,极其难以调试的bug。
一个线程空间莫名其妙被另外一个释放来,写过c和c加加的人遇到过吗,遇到过的,给老师扣个一,对装装备你莫名其妙的就没了没错,后来呢后来啊就是谈gc呢,开始聊语言的发展历史,我们我帮大家梳理一下这个语言呢。
c和c加加呢它运行起来的效率非常非常的高,呃但是呢它的开发效率很低,有的时候呢有的人呢是片面追求运行效率,但是听我说呃,现在呢有一些大规模的软件,它并不是追求你的开。
并不是追求你的你的你的运行效率有多高,也许你运行效率稍微慢一些,我拿那个硬件给你怼上去,我能接受,但是你的开发效率特别低,我就不能接受,别人用python语言,用java语言,用go语言写一个程序。
仨月写完了,你拿c c加加写,你写1年,等你推出来的时候,市场都没了,黄花菜都凉了,有用吗没用,所以后来产生了很多很多的,对内存管理比较友好的,知道吧,方便内存管理的语言,它方便方便在什么地方呢。
大家注意它方便呢并不是方便,在说那个多线程的情况下啊,没有不会产生什么不一致了,没有野指针了,不是这么回事,它呢主要方便在引入了dc这个概念,这里的dc呢指的是garbage collector。
garbage collector的意思是说哎我说哪儿错吗,garbage college是叫垃圾收集器,垃圾收集器是什么概念呢,我给大家举个形象点的例子,就是我们平时写写一些小程序啊。
就是在这块内存空间里面不断的分配对象,分配对象,然后删除掉,删除掉啊,再继续分配,再删除,这个对象呢有可能指向另外一个对象,这个对象的成员变量有可能指向另外一个对象,好在内存空间里面不断的扔这种小线团。
这小线团之间的建立各种各样的关联,也许它上下面有好多好多的成员变量,建立建立好多好多的关联等等,会形成一颗对象树,这个对象树呢在不断的动态的产生变化,如果站在内存角度来看这幅图的话。
这个图景就是这样子的,原来我们必须得小心翼翼的管理,说这块没用了,我就得小心翼翼的把它删掉,不能多删,不能不删,但是像这些语言,java语言,python语言,go语言。
以及原原来老早的这个list语言啊等等,他呢引入了一种gc的概念,gc的概念就是说我自己这个程序,我的业务程序我自己不去维护删除这个过程了,我只管分配,只管分配,那么就有必须得有人负责帮你删除。
不然你的内存不就很容易就被占满了吗,好我引入另外的另外的线程,另外的功能好,这个功能叫做gc,叫做gbletter,叫垃圾回收器,java python go都有这个这个功能,它的程序一起来之后。
它并不是说只启动你的业务线程,它会同时启动好多线程,这里面的线程就包括垃圾回收线程,ok这个垃圾回收器的功能是什么,就是你不用你再也不用管这个,你你你只管分配内存啊,应用写程只管分配。
垃圾回收器负责回收,当然这是一个很复杂的过程,因为垃圾回收器回收那些线条,不是你自己分配的,你怎么知道他什么时候就不用了呢,所以你首先你得首先找出来谁是垃圾,然后再采用各种各样的方式去回收它,我这么讲。
不知道大家能不能理解,能跟上雷老师扣个一,然后像这些程序写起来就比较简单,你就不用去管这些特别难以调试的bug,这些呢特别难以调试bug呢相对难难以产生,当然多线程的麻烦就在于。
不是说呃你这个指针被别人删掉了,这只是其中一种办法,多线程还在于说我们去共同访问的时候,数据的不一致性,这个了解过多线程的,应该我一说你就明白啊,并不是说他会把所有的这些问题全部给解决了。
不是这么回事儿,呃因此呢这些语言一旦诞生之后就开始流行,为什么,因为它开发效率非常高,大大的降低了程序员的门槛,java语言诞生之后很快就流行呃,原来学c的,学c加的很多都是转向java了,为什么。
因为它简单,在这个方面,起码在这方面比c和c加加简单的多好,这是这些语言的诞生,当然呃,每一种语言都有它自己的垃圾回收的内容啊,都都不太一样,我呢在我们的vip课里讲过,java是怎么样垃圾回收的。
讲过go是什么,垃圾回收的python相对简单,python就是使用的这种这种叫叫引用计数啊,它它的算法相对简单,但是讲到这儿呢,我也得朝我们我们我们是讲到了现在,从过去讲到了现在。
现在的这些语言很流行,但是呢这些语言有很大的问题,他也没有解决什么样的问题呢,就是java空指针的问题依然没有解决,你能保证你传给java的任何一个引用,它不是空指针吗,很难保证你有一个参数。
你接收过来之后,你是不是在java程序里面还得跟那判断判断啥,if你传给我的参数不等于空,怎么怎么办,就说这个你依然不能保证它是不是控制针,虽然java呢呃有各种各样的什么option啊,什么什么呃。
对于空指针的这方面管理的类啊,但是他依然没有解决这个问题,就是野指针的问题,依然会存在也指针问题在java里面依然会存在,ok,python里面go里面我告诉你依然会存在,这是第一个,第二个呢,同学们。
你们拿大腿想想看,作为我来说,我只管分配有另外一个人来帮我回收,那么他回收的时候一定会占用cpu的执行时间,一定会占用cpu cpu资源一定会的,所以它的执行效率相对低,所以我们说java写的程序。
python写的程序,go源写的程序相对于cc加加来说,你放心,没有人能超过他,他们的效率在长时间运行的时候一定会低,当然这些语言都自己都自己都会吹牛逼啊,说我java采用了g i t是吧。
just in time compiler啊,叫及及时编译器,采用了之后呢,我跟c和c加加差不多,你废话,你采用了之后就就是那么一小段程序和cc下,这差不多好吗,并不是说在比方说我7x24小时。
365天不间断运行的这种服务器程序上,你总体算下来,1年算下来和c和c加加的执行效率差不多,不可能好,第二一个呢,python那就更不提,更甭提了,go语言呢号称啊我是替代c的,所以我的执行效率特别高。
我比我比java还高,扯淡,go也有严重的这种垃圾回收器占用的时候,停顿时间叫s t w,就是我垃圾收集,垃圾收集起,开始干活的时候,你其他的线程都得给我停住,生产环境之中。
有人遇到过的go语言的垃圾回收,停顿时间长达数个小时,所以大家千万不要迷信一种语言,我呢讲东西呢,我是喜欢站在架构师的角度讲,我并不偏向某一种语言,但是我需要用某一种语言来落地,最流行的是java。
现在呢呃有一些地方在开始用购,所以呢我有讲价,我有讲够,其实站在一个牛逼架构师的角度来说,语言呢只是一个工具而已,作为一个结构结构化设计师,哈哈架构是吧,你要盖一座大楼的时候啊,这个柱子该用水泥。
用水泥,这个门该用木头,用木头,然后这个洗手台的该用塑料,用塑料啊,该用化工的其他化工材料,用化工材料呃,如果是从软件角度讲呢,你做你造一个非常非常复杂的软件,你这个地方该用c加加,用c加加。
该用python,python,该用够用够改用rust,用rust,所以我希望大家呢,在以后你的学习和成长过程历程里头,超越语言,站在一个更高的角度来考虑问题,建立架构师的思维。
你的薪水才能够做更高的突破,可以这么说啊,任何一种语言,包括这样的,包括python,你如果只是局限于这些语言的时候,告诉你你的薪水,一线城市目前差不多三五十万到头了,超过这个数的很少。
但是如果站在一个架构师的角度,他的心率会达到多少,120万以上,ok来认可老师这句话,给老师扣个一,java还没学明白,没关系啊,语言这东西呢,你就理解为它是一把大砍刀,你学会用斧子砍柴了。
下一步你就是用菜刀切肉,如果用菜刀切肉,你学会了,下一步你是用水果刀削水果,你说它很难吗,不难很类似,需要,你就是就是熟练度不同而已,好吧,所以这两类语言叫做有什么特点呢。
这类的特点就是它的执行效率非常高,但是他写容易特别容易产生bug,你得手工去管理自己的内存,好这是这类语言,这类语言是什么,这类语言是它开发效率特别高,但是你管理内存的时候。
你你你你你你呢它执行效率就会比较低,这个内存的管理上呢,它就会引用另外一个让别人去管,我自己不用管,我省了很多事好,那么有没有一种语言运行效率又特别高,运行效率超高,对标的是汇编c c加加。
不用手工管理内存,没有dc,ok恭喜你啊,现在它已经诞生了,这个语言叫rust,但是他也有他的毛病,学习曲线巨高,ok,这是rust呃,有同学非常的好奇,说老师这事儿很神奇啊,运行效率特别高。
what跟c和c加加差不多,然后你你你只管自己去往内存里头分配,就可以了,你不用管回收没有g c a哇,他是怎么做到的呢,rose没听过是吧,你罗你太落伍了啊,你是这行业混的吗。
你稍微稍微关注一点最新的技术的发展,大哥希望大家伙儿的学习叫做与时俱进,这词儿呢非常的重要啊,咱们入了这个行业,你要想不学习就能持续不断往前发展,不可能的,那就是温水煮青蛙,把你自己慢慢煮死,好吧好。
大家看这里啊,这个rest呢是比较新的一个语言,它的特点就在于这,它运行效率超高,和c和c加差不多,但是开发效率也并不低,原因是什么,原因是你不用手工去管理内存,你只管去分配就行,你不用管回收牛刀吧。
好他主要是怎么做到的呢,你想听吗,今天其实主要讲jvm的gc的,要顺带着给大家讲一讲好吧,看这里,我我告诉大家一个特别,他特别特别牛的一个概念,他特别牛的概念叫什么呢,叫ownership。
叫ownership,所有权,所有权的概念,这个所有权概念是什么意思呢,所有权的概念就是这里面的每一个值。
rust。
就是这里面的这,这这这个这个这个这个任何一个值啊。
任何一个值都归属于一个变量,就是一个变量代表一个值,一个变量指向一个值,任何一个值都归属于一个变量,然后有且只有一个,不可能有多个,这句话什么意思,我形象一点解释。
我告诉你在这张图里面我们会有多个变量哈,这叫一个变量,o是一个p是一个啊,这里o是一个p是一个,还有多个变量指向同一个值,或者叫同一个对象,在rust里面这件事情不可能发生,哈哈听懂了吗,我再说一遍。
go on的gc,z b c的一种算法,接近于它啊,类似,好大家看这里我再说一遍,重新重复一遍,就是多个变量指向同一个对象,这件事不可能发生,只会发生什么呢,同一时刻只会有一个变量指向这个对象。
这就是所有权的概念,叫做我们这个值的所有者只有一个一夫一妻制,哈哈不知道大家听清楚没有,那有同学可能就会说了,老师这有什么好处吗,来你们拿大腿想一想,小伙伴们,假如我在占空间。
任何一个战争里面的变量指向的这个空间,如果确保是一夫一妻制的话,那我这个我们叫她丈夫吧,她的丈夫消失的时候,他的妻子是不是顺带着就殉情了,听懂了吗,再说一遍,她的丈夫死掉的时候,什么时候死掉了。
还记得吗,他的妻子就跟着殉情,自动就给你回收了,你发现没有,没理解是吧,听我说还记得占空间里面它的特点是什么,占空间特点是当我这方法结束了,我这占空间就不存在了,我这方法结束了,占空间不存在了。
哎我们假设如果这个p你已经确定它不存在了,同时是一夫一妻一妻制,没有任何其他人指向这个对象,你们好好想想看我这个对象是不是可以回收了,方法结束站空间里变量指向的任何空间,跟着回收就可以了,听懂了吗。
也就是说我不需要gc,为什么不需要dc大哥,你你这边你这边消失了,我给你加几行代码,把这个里面关联的编译器帮你自动加的啊,关联的内容ok直接就给你干掉了,所以,这是rust的它的一个核心的设计理念。
rust的这个特点诞生之后啊,同时在和堆叠加了它的这种对于多线程访问的,呃,共共共共享变量,必须你得你得需要采用它特定的书写机制,才能够写得出来,它会产生了一个特别奇妙的东西,叫做你写不出bug来。
好说一下,这是rust语言特别有意思的地方,叫做,ok不知道的,不知道大家听清楚没有,你只要程序的语法能过,就不会有bug,当然他语法非常特殊,这讲着讲着怎么讲成rust了。
逻辑bug是任何语言都存在的,任何程序都躲开了大哥,逻辑bug是啥,你本来让你计算这个程序的一个人的年龄,你给计算成为一计算成为一个人的体重了啊,本来让张三娶了李四,你非得让他娶王五。
那这种bug我你这跟语言有半毛钱关系吗,是吧,所以这个语言没关系啊,咱们说语言层面的bug,rust呢消给你消失,消了很多,除了我刚才说的这个ownership之外,除了还有呢就是在多线程的这种写法。
多线程写法叫做固定的,你知道吗,你就得这么玩,你不这么玩的话,你根本写不出来,你想让多个线程去访问同一个值吗,我告诉你,你只有这种写法,你不用这种写法,你根本就写不出来,所以只要你写出来就没bug。
就是这么的牛叉,啊我不知道我大概说清楚没有啊,但是咱们今天还是还是得说回来啊。
今天并不是讲rust的,不感兴趣对啊,不敢去算了,反正你们对新的东西也不太感兴趣,我们讲老的吧,咳咳咳咳,讲这边啊好了,这是语言的大概的一个发展的历史,你要你要明确啊,现在这个语言呢大概分这么多类。
那有同学说老师那js这种东西是什么,其实这些都是带垃圾回收器的好吧,就js这些啊,还有像什么,还有还有想其他的啊,这colin等等,这不说了,他本身就是运行在jvm上的,所以他肯定是带了就回收器的啊。
还有像什么scala,就老师给你讲东西呢,我希望讲那个层面太低了,我希望你站在更高的角度上来教你认识啊,就整个一个it界的一个发展,还有呢整个语言上的语言层面上的一些东西。
你站在更高的一个角度上建立起来,你的知识体系。
系列 6:P38:JVM的GC历史 - 马士兵学堂 - BV1RY4y1Q7DL
rust有啥缺点,rust缺点就是学习曲线居高嘛,特别高,好同学们讲太多了是吧,嗯已经九点了,what确实是啊,我们来聊聊那个jm的gc的历史啊,疲惫了是吧,嗯a了,已经疲惫了,不会吧,你们还活着吗。
我们可以继续吗,这还没开始dc呢,没开始就没开始吧,就业咋样,就业不怎么样,因为rust刚刚发展,我们静观其变,我是喜欢让我们自己的学员,都站在业界的最前沿,就是你要抬起头来看看整个行业发展。
站在整个业界最前沿,你就能发现更更加优秀的机会,发展机会的时候,你能扑上去啊,做好准备,好看这里我们来聊聊gm的dc的历史啊,就这块的内容呢,我稍微补一点最基本的这种技术上的概念,我们先来说呢。
到底什么是一个垃圾,就是我们刚才说嘛,如果是你呃,采用这种引进垃圾回收器的,这样的一些个语言的话,那你你总得找出来,就是业务线程在这里不停的扔线团,扔线团,扔线团。
线头和线条之间的有各种各样的线来进行关联,好作为垃圾回收线程的角度来说,我得去定位啊,这这这这到底哪个是垃圾,哪个线程是垃圾啊,怎么找啊,这里面的找法呢一共有两种啊,这什么是垃圾,我们先定义什么是垃圾。
这垃圾呢其实很简单,就是你看这你看下面这个对象,这个对象呢在运行的过程中,没有任何引用指向它了,原来的一个成员变量的引用指向它现在没有了,好这哥们就是垃圾是肯定的,没有人没有引用指向它的,好。
它就是垃圾,但是我们怎么定位这个垃圾呢,定位这个垃圾的话有两种方式,第一种呢就是reference count,你看一下,看一下动画就理解,就这个对象呢,我给他做一个计数引用计数法,这叫有三个。
目前有三个引用指向我,我脑袋脑门上写了一三啊,接下来如果有一个已经消失了,变成二,有一些用消失变成一,有一个消失变成零,当它变成零的时候,这哥们儿成为垃圾,python就是使用这样的方式。
这个叫引用计数法,引用计数法有毛病,毛病在于哪呢,我们假如说有一堆垃圾,三个垃圾a指向b b指向c,c又指向a好,所有的对象都有引用指向,但是没有任何其他的引用指向,这三个对象中的任何一个啊。
这叫做三个垃圾,一堆垃圾,一坨垃圾,那么像这样的话,如果你用reference count的方式就找不出来,因此java里面采用的并不是这种方式,怎么定位一个垃圾,java里面采用的是这种方式。
叫做根可达算法,叫做research,这算法一说你就明白根可达算法的意思是,我们从根儿上开始,什么叫根may函数里面,简单理解may函数里面的一个一个变量,这就是根儿就没函数,通过这根线来跟着捋。
捋到谁谁就不是垃圾,它的成员变量又指向了它,它的成员变量又指向它,又指向它,又指向它,好,这几个全部是垃圾,顺着这根线找,找不到谁的时候,树的搜索算法找不到的,这些全是垃圾,这个大家能听明白吗。
有没有同学有疑问的,循环引用不能把引用断开吗,人家业务逻辑就要循环引用,你为什么要给人断开,你断开人家业务逻辑不变了吗,大哥,当然大厂面试的时候呢,有一个问题叫做什么是根儿啊,如果要讲这些细节的话。
我我倾向于讲东西呢是先从很高的层面来讲呃,我建议大家学东西,学学课程也是一定是要什么呢,先建立知识体系,这件事情超级重要,有很多人呢连最基本的学习方法都不会,可以说啊,从小学到大学学了这么多年。
最基本的学习方法没学会,一定要先建立知识体系,然后再去查漏补缺,我讲的再形象一点,你掌握一棵知识树的时候,先把树干给我掌握了,然后再去掌握树枝儿,然后再去找我书页,你的树干和树枝子。
你看你的树干只要是特别稳固的话,你树叶想刮多少刮多少,现在很多的碎片化的学习,都是让你掌握书页的知识,你掌握了多少书页都没有用,因为你没有建立整个树干的体系,了解一个庐山,你得坐着飞机从上空飞过。
看庐山的整个面貌,而不是说你到庐山脚下某一棵树底下,去研究庐山的蚂蚁窝,这种纯属扯淡,听我说我上了这么多年学,我记得我上大学的时候,有一个学期把清华图书馆所有的物理书,那藏书很多的啊,大概得有几万本一。
一个学期我全把它全把它看完了,当然没记得多少,但是整个物理的体系慢慢就建立起来了,呃小伙伴们,你们呢如果不同意这个说法的话,我不管你同意不同意,你采用一下,你试试看,就知道要先要先建立知识体系。
听懂了吗,建立知识体系之后,再去研究那些细节好吧,知识体系的建立呢就是囫囵吞枣,四个字叫囫囵吞枣,有好多人学东西啊,特别好玩呃,他在学习的过程中,假如说这是一棵知识树嗯,他在学习的过程中。
他学到某个节点的时候,它会顺着啊,就每一个细节,比如说别人给他讲dos窗口,你怎么设置环境变量啊,咱们学java的人一般都会遇上是吧,怎么设置环境变量,怎么设置pass class pass。
他就开始研究哇,这dos挺好玩的啊,这dos还能写b a t这这这这个b点,这这脚本语言的啊,我研究研究这个脚本语言怎么玩吧,然后啊这道德窗口怎么产生的呢,研究显卡行行行行,哎呦哎玩玩ps,我跟你说。
完蛋,你要这么学,你的时间就全部浪费,没有用,而是你应该怎么学呢,先二话不说,把整个这些关键的点全拿下,拿下之后呢,再去发散,再去纠细节,我大概就是这意思好吧,嗯那就是想先看完本书呗,行行行。
你这个理解能力我也是醉了,看来我还是我表达不够啊,sorry,好我讲到这儿呢,我是希望大家呢先把这个什么是根,这件事呢先略过,不要着急,因为如果作为,呃官方的非常规范的定义来说,你得去看哪本书呢。
叫jvm,叫java virtual machine specification,那这本书呢是在oracle网站上可以下载,它的全称叫做jvm的虚拟机规范规范大哥,他很枯燥的。
也只有像老师这样特别无聊的人才会去读他,其他人你不用读,所以根来说这本书上给你说的非常明确,它包括这么几部分内容,jvm stack的内容,stack jan native method stack。
又是jan runtime constant prove,运行时常量常量池,steady reference in method area,方法区里面的静态引用,以及我们的class类的对象。
这里面的任何一个拿出来,你不了解jvm底层,直接就把你给看晕了,所以你不用管根嘛,我给你举个最简单例子就行了嘛,main方法里面的有一句话叫object小o等于new object,好。
这哥们就是格听懂了吗,很简单,就是方法整个程序开始执行的地方,最先建立起来的那些对象,这些哥们儿叫歌叫root,专业说它就是gm stack里面的内容,stack站里面的。
我们那边方法里面不是为我们县城站吗,主线程站,对不对,这里面对象get了吗,好我们可以继续吗,先把它略过好不好,所以从根上开始找,本意就是从根上开始找,反正是顺着根儿捋捋捋。
就是我我还是喜欢讲的稍微形象一点啊,形象一点就是你比方说你嗯,你女朋友,你男朋友啊,你们哥仨,你们姐仨啊,甭管是哥仨姐仨,在一个空间里面,内存里面扔小线团,谁是根儿啊,你们仨就是根儿。
你们的手捋着这个小线团,捋到的全都不是垃圾,凡是捋不到的,中间那个线给断了的,全都是垃圾,就这意思,这样的话呢,你就不会给产,就是那种原来像这种互相引用的,但是哎你顺着根,只要找不着他,这根俩就是垃圾。
知道吧,这是第二种算法,叫根可达,非常简单啊,当我们知道了什么是垃圾,当我们定位了什么是垃圾,定位好了之后呢,我们要把它给清掉,对不对,好清除算法从上个世纪60年代开始发明的,到现在为止,几十年过去了。
就这三种清除算法,就这三种,这三种是啥呢,第一种叫mark swift,第二种叫copy,三种叫mark contact,背包就行了,特别简单,仔细看,第一种叫mark sweep,就是我找到了标记标。
把它标记成为垃圾之后,把它给清掉,就这么简,原来ok这哥们是垃圾了,怎么办,打上个标记,说这块空间可用了,可以可以使用了,后面的人可以在这里面分配内存了,搞定,梦洁说什么情况,根部可达,没想出来。
我的老天爷呀,梦洁你是玩语言的吗,object o等于new object好,这里有个小o指向它,我写o等于空来,你告诉我这个o指向谁,这个引用还有没有,贝儿,让我忍住怒火,继续给你们往下讲。
开个玩笑啊,嗯总是有2年没睡了,开玩笑开玩笑啊,我们回一回的气氛,听课听着怪累的,稍微聊会儿,小甜甜k好,我们来看这个标记清除啊,要清楚的意思就是诶我们简单说吧,我们顺着根开始找,找到的全都不是垃圾。
这些找不着的全是垃圾,怎么办,把它们清掉,哎,这就叫标记清除,简单吧,就这么简单嗯,找到的这些全都不是垃圾,没找到这些全是垃圾,怎么办,清掉咔嚓咔嚓清掉好标记,清楚标,清除这种算法嗯,虽然说比较简单。
但是有它的毛病,毛病在哪呢,当我们好多好多次运行,运行很长时间之后,你会发现这也有清掉的部分,这也有清掉的部分,这也有清掉的部分,这也有清掉的部分,你会发现你的内存变成了碎片化,特别严重。
碎片有好多有好多洞,然后这时候你要是想来了一块大的空间,我想分配下去,你发现你找不着了啊,碎片化特别严重,好嘞,当然呃,第二种算法没有碎片化,但是也有它的毛病,第二种算法叫拷贝,拷贝也特别简单啊。
认真看,其实啊就很简单,不管你们家多大,你们仨只能用一半,你女朋友你男朋友好,在里边玩吧,随便玩随便折腾,折腾完了之后呢,我的垃圾回收器进来了啊,你妈妈拎着一把笤帚就进来了,他进来之后干了一件什么事呢。
顺着你们仨开始这根开始找找找找,找出来的东西,整体性的全都复制到另外一半里面去复制过来,同时排列好,看到了原来那个没排列好的哎,都给它排列好,然后把左边这半边整体性的全部回收,ok这个算法也简单。
效率越高,但是我相信你那大腿想一想,也应该知道他的毛病之所在,还用我说吗,浪费内存,没问题吧,很简单啊,我们在聊第三种叫my compact,my comment,什么意思啊,这就更简单了。
就是既然第一种呢碎片,第二种呢浪费内存,干脆呢我就在回收的时候直接把它整理好,什么意思,再说一下你你女朋友,你男朋友好扔小线团,然后运行的过程之中呢,产生了各种各样的垃圾,当我在回收它的时候。
我顺带着把内存整理一下,整理成什么样的,整理成排列的,整整齐齐的排排,坐吃果果,你们仨在这后面的,有用的,在后面跟着好,剩余所有的空间都是可以用的,very good,这叫标记整理,叫标记压缩。
这种算法也很形象,就是你的你的硬盘的碎片化整理嘛,他也没有这种内存的碎片化,它都是连续的空间,但是问题就出在效率很低啊,它是这三种之中效率最低的好,一共就这三种,从上个世纪60年代开始到今天,我告诉你。
就这三种,没有别的,不知道说清楚没有,这块有疑问吗,很简单吧,听我说,所以呢,看这里啊,就这三种算法呀,我的中文呢中文,就这三种算法都有毛病都有毛病,就是说你要是把你的内存当成一整块的时候。
无论你采用什么样的算法,都有它自己的问题,所以垃圾回收器非常聪明,它呢是用这三种算法综合运用,然后同时对内存进行了划分,产生了各种各样的不同的,形成自己个性的垃圾回收器啊,妈妈你爸爸爷爷奶奶。
叔叔阿姨都可以帮你来进行垃圾回收,但是每一种都有它自己的特点,好同学们,下面我们看垃圾回收器总的图,垃圾回收器的总图,未来放在这儿啊,好那这是垃圾回收器的总图,那么大家听我讲啊,这垃圾回收器总图呢。
在jvm从jdk一点零诞生到现在,jdk 14从一点到14,一共诞生了十种垃圾回收器,这时钟垃圾回收器,我一会儿呢沿着历史我慢慢给你捋出来,你就理解了,这时钟来机回收器它到底是怎么玩的了。
每一种的特点是什么,好我们先来把它背过,有同学说老师你这个东西要背过吗,没错你跟面试官想吹牛逼,或者你想把他吊起来打的时候,你就把它给背过,但是它也不难,这几种垃圾回收器呢,你我你先花个几十秒。
先大概看一眼,分成什么呢,分成是把内存分成两部分的,以及把内存分成多部分的,好看这里前面这六种是属于内存分带模型,后面这三种呢属于内存不分带,但是g one呢它逻辑是分带的。
econ是一个特别好玩的垃圾回收器,叫做他是他是什么都不干的垃圾回收器,好听我讲,我一个一个啊,今天是已经9。20了,没关系,我一个一个的给你们捋清楚,好吧好。