00:00
好,同学们,接下来给大家介绍一下SYNCH的性能变化,那么来给大家说一下无所偏向,轻量重量所它们之间的演化,前因后果,来龙去脉,为什么会形成这样锁的升级过程?走首先在JAVA5之前啊,现在我们本堂课本节都说过,我们目前主流是JAVA8,那么在JAVA5之前的话呢,是只有S的。这个是操作系统级别的,什么重量级操作,那么开玩笑的一句话就说以前啊,比方说加二四。只有要么就别加锁,要么直接就是重量极锁,直接捅到重量级锁好,那这个时候呢,控没控制住,当然能控制住了。只要加了尤且仅有一个线程访问,问题是这个是一个什么操作系统级别的重量极左,牵扯到底层用户态和内核态之间的交换和上下文的切换。那么来。重量级所,假设所的竞争比较激烈的话,性能会急剧下降,为什么假设这是个资源类,我现在有且只能有一个进来,并且假设它干的呢,也比较时间长啊,比如说一两秒钟才完成他的业务逻辑。
01:11
那么外面在高并发下面没什么好说的,大家只能在这排队,那么这个时候如果他用完了要出的,大家要去强索,就牵扯到了用户态和内核态之间的转换,这个是重点,那么请大家跟着我来。首先。在操作系统层面看来啊。用户态,也就是我们Java程序员编写的程序,那么这个内核态,那么就记着,如果在JAVA5以前,Think啊,这个是什么?我们前面也讲过,是由底层加那些虚拟机的关键字所搞定的,OK,那么它是这样,那么它呢,是Java的线程是映射到操作系统的原生线程之上的啊,我们都晓得Java,你th.start那个方法,底层是调的START0,实质而言是线程调的是底层操作系统的,那么也就是说我们要阻塞或者唤醒一个线程,就需要什么操作系统介入,哎,我不是在程序层面我就可以搞定的,我自己编写的程序,我们说过Java一再强调过这个东东,对吧,是什么native。
02:12
还记不记得start了以后在这块是不是有个START0NATIVE,也就是说到这278 728行之后,Java的势力范围到这就没了底层操作系统说了算了。所以说我们只要操作多线程的动作是需要操作系统介入的,那么就需要在用户态和核心态也是内核态之间切换。这种切换是会消耗大量的系统资源的。用户到系统,系统再到用户,那么这个时候。因为用户态和这个操作系统内核态各有各自专用的内存空间、寄存器等等,那么切换的过程当中有些状态的消失变换。变干都要互相的传递,那么所以说这种情况下就是我假设啊,我一个程序C子的O,一个线程A,我要获取所,如果能够获取得到,那么好加锁成高内核肽,告诉你目前是哪个线程所持有,我们前面是讲过C语言的底层的object,莫塔那个东欧有个字段能不能保证,然后告诉你获取成功,这还是顺利的,那么如果在高并发下面,那就麻烦了,一个人进去锁住了完成业务逻辑。
03:22
后面的那些呢,就会获取失败,线程就会被阻塞,然后呢到一个阻塞队列里面去安排去排队,等他释放完了以后,这波被唤醒又过去,那么这样的切换成本是极高的,所以说在加入了早期版本当中,C属于什么重量极锁效率低,因为监视器模拟塔就我们的管程是依赖于底层操作系统的new text lock叫系统的互斥量,也就是我们所说的锁来实现的。那么挂起线程和恢复线程大家请看用。这个线程来了十个,只能有一个成功,那九个只能是去阻塞,只能是去等待,那么这个时候他们呢,挂起恢复都要转入内核态去完成,那么阻塞和唤醒和Java线程需要操作系统切换CPU的状态来进行,那么这种状态是耗时费力的。所以说。
04:12
这种情况下,我们就会发现,如果你你的业务逻辑的状态。很简单,但是为什么一个简单的操作有点类似于什么高射炮打文字啊,杀鸡用牛刀,那么这样的话呢,就是这种切换的时间可能比用户代码之间的时间还长,得不偿失,时间成本极高。那么这也就是为什么。早期的生空奈子效率低的原因,它确实给你解决了安全一致性问题,加了锁,每次只能进来一个,但是性能不大好。所以说我们就想,那么在后续的研发和优化当中,或者port Java虚拟机就会认为,那么我们为了减少所和示范所所带来的性能消耗,我们能不能说不要?频繁多次的从用户态和内核态之间这样的切换,能不能找点折中的,哎,那么这个时候我们就引入了轻量所和偏向所好,那么这个时候就是他们为什么来的一句话,就是尽量的减少用户态和内核态之间的切换,因为他们容易导致什么阻塞,能不阻塞我们就不要阻塞,实在不行了才能到内核台去切换,OK,也是什么极致上的优化,好那么这个动作说完了以后,我们来复习一下前面的知识,为什么每一个对象都可以成为一个锁呢?
05:32
怎么来?底层C加加open jdk的源码给大家抓好,这也是我们前面说过的管成mark op,那么说说过一个东西什么?这个时候有一个东西叫object莫的这么一个指针,它有个管程对象,那么返回的,那么就是每一个对象你都可以作为一个锁,那么来它呢,这个莫塔就是我们的管程,就是一种同步工具。那么它呢?也是什么?任何一个加va对象,那么加va对象天生就具备模塔,每个加构对象都有成为模的潜质,因为在加构设计当中,每一个架构对象自打娘胎出来就带了一把看不见的锁,这个就叫内部锁,或就是我们所说的管程。
06:13
管成所,那么大家都写过这样的代码,假设我这有个类,有个main方法,里面你有那个object,随便你有个什么。扔到这都可以,为什么?因为每一个对象都有个object模,它都可以成为锁,那么这个模的本质啊,就是依赖于底层操作系统的new text lock,就是互斥这种重量级的锁。所以说操作系统级别啊,如果你一口气直接捅到重量级锁,那么实现线程之间的切换,就是多次完成用户态到内核台的转换,成本极高,所以说逼不得已尽量不要走到这一步,OK,那么这样。是第一个知识点,第二个我们来看一下它的监视器所来复习之前的object模拟。也就是说在这块这个object monitor,好,这是一个指针,那么接下来这个object监视器所它里面有哪些内容,这张我们都前面都见过吧,那么它呢,是由他来负责进入和退出管程对象的这种实现的,每一个对象都会有一个莫妮,他呢伴随着呢对象一起创建和销毁。
07:14
那么来这个呢,是在我们open gd k8C语言的那些啊,由于它的层级比较深,我就不打开了,给大家抓出来,这个我们前面说过,比如说现在持有当前这个莫塔的是哪一个欧,哪一个线程所持有,包括如果说你胃疼t find的一些东东,或者被阻塞了,要去等待。那么搁搁这儿等着就加到这个set,然后呢。各种阻塞啊,或者是处于等待锁的block的状态呢,又会进入到这个列表等等等等,前面都给大家说过,那么这两者也就是说他。就是他一回事,那么我们就会明白啊。对于我们的text lock就是互斥的这个码锁,Java虚拟机底层实现底层呢,就是依赖于这么一个动荡。那么。
08:02
我们呢,就会得到size是Java语言中的一个什么重量级的操作,那么这个模管程和Java对象以及这个线程是如何关联的呢?那么大家都清楚这O呢?是不是协定你哪个线程来持有这把锁了?所以说如果一个加法对象被被某个线程锁住并持有,那么该Java对象的马字段中的洛克沃尔指向莫塔的起始地址。OK,那么第二个模,他这个对象的欧字段会存放拥有关联对象所的线程ID,我就告诉你是哪个对象所持有。他占用,那么所以说在这块我们这个时候它持有的时候,抱歉牵扯到了操作系统的内核态,那么在这个转换过程当中,是需要耗费很多处理器的时间的。好了,那么结合我们之前的对象头,我们来给大家说一下。这张图我相信大家都见过,以前为了减轻大家的工作量和学习量,我把这块删掉了,这块给你补全了size,假设某个对象,任何一个对象都可以,每个对象我们说过了,分对象头。
09:10
实例数据和对齐填充,那么实例数据就是你定义的,其实就是头体鞋字嘛,还记不记得我画为人形,那么任何一个对象头又分为马尔对象标记64位和k point,那么指向创建这个类的模板的那个马夹,那么对于这个挖二的我们就知道了,任何一个对象我们就看它里面这些状态,我就知道是哪个线程持有锁,哪个线程所占用,那比如说无所是。多少零幺,为什么所的标志零幺,OK,倒着看就是001,那么这101,那么就是什么偏向所?各位同学看101,那么轻量所是零零,重量所是幺零,以前没有偏向所和轻量所,直接就从无所干到重量级所,那么这个时候重量级锁哪个对象持有这个锁了?那么自然而然牵扯到C开发的这个object莫塔,那么这个东东是个什么?
10:03
在这儿已经一再的给同学们强调并讲解过了。OK。那么在这。我们来看,那么这个呢,换以前直接到重量极所,那么指向对象监视器的这个指针就是这个O的模塔,指向它欧锁定当前对象的线程ID countt,那么表示对象是否被锁定了。这个呢重入,这个呢阻塞,这个呢等待等等等等,那么我们说过,对于这个同步代码块,以前我们就说过了ENT exit加锁和解锁每一步。怎么个走,就对应着这个object模,这个对象头里面的这些状态位的标识和变化,该不该加,什么时候进去,什么时候出来,该阻塞的阻塞,该排队的排队,那么最后解锁的话,这边有加,这边就有解,那么最终我们表示如果说owner擦除滞空了,表示这个线程完全释放了,所从S当中全部退出,这个是我们以前的详细给大家说过,那么只不过结合我们对象头,那么就是这么一张图。
11:09
说穿了就是加索引号玩。这些64位mark的状态标志决定这个object模里面这些内容的登记信息的变更,让操作系统和底层明白了哪个线程持有锁是可是不是。递归所使有了几次啊,几个lock就有几个洛克等等等等,均在这张表上面给同学们详细说明好,那么从这是JAVA5以前,那么所以说从JAVA6开始,我们大家都得到一个共识,用户态到内核态是非常耗时的,尽量不要一次性捅到那,那么所以说JAVA6之后,我们为了减少获得锁和释放锁所带来的性能消耗,就引入了轻量级锁和偏向汽油。偏线索,那么这个就告诉大家。无锁偏向轻量,重量需要有个逐步升级的过程,你别一开始就捅到重量级,所这样呢,一开始杀机用牛刀就要牵扯到系统底层级别的。
12:07
内核肽得不偿失,所以说这个就是我们引入新子底层各种所得升级策略和性能变化,它的来龙去脉和前因后果。
我来说两句