学习笔记---锁的膨胀升级

锁的类型存放地 —markWorld

markworld 是对象头的一部分,他的主要功能是 存储 gc标志,是否可以偏向,锁的类型,hashcode,分代年龄,以及与锁有关的线程信息,所以要了解所得升级先要了解markWord是什么样的

markworld 以二进制的形式总共的存储64bit

#HashCode信息

位于markworld的26bit~56bit
在计算过hashcode之后,hashcode信息会记录在markworld上

偏向锁信息

位于markworld的1bit~54bit
在允许偏向线程的情况下,首个线程进入对象时记录相关进程信息

轻量锁与重量锁信息

位于markworld的1bit~62bit
在发生竞争后,记录当前持锁线程的信息

锁标志位

锁标志位在第63~64bit(二进制) 是记录锁的类型
01:偏向锁 00:轻量锁 10:重量锁 11:gc标志

性能方面 偏向锁>轻量级锁>重量级锁

是否允许偏向锁 标志位

位于偏向锁的62bit 表示这个对象可不可被偏向
1:表示可以被偏向 0:表示不能被偏向
无锁状态:偏向锁标志为0 ,锁状态为01

什么时候可以偏向?什么时候不能偏向?

由于偏向锁信息 占有了54个bit,并且单个线程的情况下偏向线程信息不会发生改变。
而hashCode 却占了31位, 偏向锁线程信息与hashCode的存储位置会发生了冲突。
所以在计算hashcode之后,由于没有足够的空间存储偏向锁信息,所以偏向锁标志就变为不可偏向。
值得一提的是,如果记录偏向锁之后再计算hashcode,那么偏向锁会膨胀成重量锁

锁的加载

偏向锁

在对象没有初生成的时候,是处于匿名偏向(可偏向但是没有持有偏向锁)状态
加锁开始后,jvm会在栈帧中创建个lockRecord,并将lockRecord中的objectRef指向加锁对象

在线程中生成偏向自己的header通过cas操作将线程信息存入对象的markWorld当中,此时的对象会记录下第一个线程的线程信息, 锁标志位不变,还是101

偏向锁加锁为什么快?
因为在相同的线程第二次进来后,jvm 会在几个简单的if判断(对象是否是允许偏向,是否偏向当前线程,对象是否过期)后就可以执行代码块,所以线程第二次进入后偏向锁的的性能极高

偏向撤销
需要等待安全点的出现,暂停并检查持有偏向锁的线程,如果偏向线程存活,则执行完相关栈,并且遍历所有的锁记录,将锁记录和markworld 重新偏向或者变为无锁。如果不存活,那就简单了,直接将markWorld 改为无锁状态就好。 --------由此可见偏向锁撤销对性能是有很大的损害的

偏向锁的缺点
偏向锁虽然带来了极高的性能,但是当撤销偏向锁的时候,却会带来的性能上的损耗(),所以许多的jvm都设有偏向延迟(默认4秒)

批量撤销,过期
当一个类 被实例化了多次,并且所有的类都被相同线su程持有偏向锁后
此时b线程进来拿锁,因为是不同线程,锁会升级成轻量锁,但是在20个对象都被b线程持有锁后(类的偏向锁被撤销了20次),这时markworld当中代表着过期 eq会发生变化,即过期,jvm会将重新降级成偏向当前加锁线程的偏向锁

随后该的对象被c线程加锁多次,那么再次撤销20次之后,之后新生成的类的对象,将默认是轻量锁,并且不会在被降级

轻量锁

什么时候进入轻量锁?

当对象已经有偏向线程后,另一个线程来对对象加锁。
对象中的偏向锁会撤销,新的线程将持有轻量锁

轻量锁 加锁全过程
和偏向锁一样,jvm会在栈帧中创建个lockRecord,并将lockRecord中的objectRef指向加锁对象,并将markWorld复制到锁记录当中。

线程对对象加锁后,jvm会先判断当前对象是否可以执行偏向操作(对允许偏向,过期,匿名,偏向本线程)进行判断,在内存中生成偏向当前线程的header部,然后通过cas修改,因为markworld不是偏向当前线程,所以加锁失败,进入轻量加锁流程

(1)撤销偏向锁(撤销完成后markWorld处在无锁状态 标志位001)
(2)在堆中生成个无锁的markWordld对象(标志位 001)
(3)通过cas的原子操作 将新生成的markWorld 与对象中的markWorld做比较,如果相等,则替换markWorld为指向 lockRecord指针,标志位变为(001 -》000) 加锁完成
(4)执行完代码块。会释放锁。将对象重新变回无锁状态(001)

轻量锁都是交替执行的,因为一旦撞车,就会升级成为重量锁

重量锁

重量锁的场景就很简单了,发生了抢锁。以及对象计算了hashcode 也会升级成重量锁

膨胀重量锁,其实是cpu从用户态升级成内核态。因为可能会调用操作系统里park方法。

在锁膨胀成重量锁之后,并不会马上阻塞,而是开始自旋,当自旋多次依旧无果后,才调用park方法

关于锁升级的类比----之家里有个胖厨师

(1)胖厨师(新的对象)刚来的时候其实不知道主人喜欢什么(匿名偏向
(2)第一天(第一个线程加锁)主人(线程1号)说喜欢川菜(加锁
(3)于是从那之后胖厨师的采购单上都准备这川菜的材料(加锁后,偏向锁偏向“线程1号”)。
(4)之后几天 主人对胖厨师能够快速的上菜表示满意(偏向锁后,同线程性能快
(5)这天来了女主人(线程二号),胖厨师(偏向线程 “1”号),不得不把联系订货商将定好的川菜食材给取消了(偏向撤销),等待女主人的吩咐(处在无锁状态
(6)女主人(线程二号)喜欢吃甜,于是胖厨师准备了甜点(标志位处在轻量锁状态
(7)女主人吃完后,胖厨师就没有去准备川菜的材料,而是等待主人们的命令(处在无锁状态,不会降级成偏向锁
(8)有一天男主人(线程1号)想吃川菜了(轻量锁加锁),胖厨师在做饭的过程中,女主人(线程二号)要吃甜点(线程二号尝试抢锁
(9)胖厨师由于没空(线程2号抢锁失败
(10)于是将女主人的请求向后推迟了(线程2号进入sleep
(11)女主人很生气,和男主人吵起来了(膨胀成重量锁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《Python学习笔记》是由皮大庆编写的一本关于Python语言学习的教材。在这本书中,作者详细介绍了Python语言的基础知识、语法规则以及常用的编程技巧。 首先,作者简要介绍了Python语言的特点和优势。他提到,Python是一种易于学习和使用的编程语言,受到了广大程序员的喜爱。Python具有简洁、清晰的语法结构,使得代码可读性极高,同时也提供了丰富的库和模块,能够快速实现各种功能。 接着,作者详细讲解了Python的基本语法。他从变量、数据类型、运算符等基础知识开始,逐步介绍了条件语句、循环控制、函数、模块等高级概念。同时,作者通过大量的示例代码和实践案例,帮助读者加深对Python编程的理解和应用。 在书中,作者还特别强调了编写规范和良好的编程习惯。他从命名规范、注释风格、代码缩进等方面指导读者如何写出清晰、可读性强的Python代码。作者认为,良好的编程习惯对于提高代码质量和提高工作效率非常重要。 此外,作者还介绍了Python的常用库和模块。他提到了一些常用的库,如Numpy、Pandas、Matplotlib等。这些库在数据处理、科学计算、可视化等领域有广泛的应用,帮助读者更好地解决实际问题。 总的来说,《Python学习笔记》是一本非常实用和全面的Python学习教材。通过学习这本书,读者可以系统地学习和掌握Python编程的基础知识和高级应用技巧,为以后的编程学习和工作打下坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值