synchronized的锁升级和锁膨胀

本文将将讲解java中synchronized从偏向锁逐步走到轻量级锁、自旋锁再到重量级锁的过程,以及java8中的锁降级优化。

偏向锁

偏向第一个拿到锁的线程。

即第一个拿到锁的线程,锁会在对象头Mark Word中通过CAS记录线程ID,该线程以后每次拿锁时都不需要进行CAS(指轻量级锁)。

如果该线程正在执行同步代码块时有其他线程在竞争(指其他线程尝试CAS让Mark Work设置自己的线程ID),会被升级为轻量级锁。

如果其他线程发现Mark Word里记的不是自己,且发现原持有偏向锁的线程已经执行完同步代码块,会尝试CAS把Mark Word中的改为自己的线程ID。

轻量级锁

轻量级锁就是通过CAS进行加锁的。

JVM会给线程的栈帧中创建一个叫锁记录Lock Record的空间,把对象头Mark Word复制到该空间里(Displaced Mark Word),并通过CAS尝试把原对象头Mark Word中锁记录指针指向该锁记录。如果成功,表示线程拿到了锁。如果失败,则进行自选(自旋锁),自旋超过一定次数时升级为重量级锁,这时该线程会被内核挂起。

自旋锁

轻量级锁膨胀为重量级锁前,线程在执行monitorenter指令进入等待队列时,会通过自旋去尝试获得锁。

如果自旋超过一定次数时还未拿到锁,就会进入阻塞状态,等待内核来调度。此时会发生内核态与用户态之间的上下文切换,所以会影响性能(引入自旋锁就是为了减少这个开销)。

因为后面的线程也进行自选尝试获取锁,所以这对于已被阻塞的那些线程来说,会不公平

重量级锁

重量级锁就是通过内核来操作线程。因为频繁出现内核态与用户态的切换,会严重影响性能。

升级为重量级锁时会在堆中创建monitor对象,并将Mark Work指向该monitor对象。monitor中有cxq(ContentionList),EntryList,WaitSet,owner

d4HTbR.png

锁降级

Hotspot在1.8开始有了锁降级。在STW期间JVM进入安全点时如果发现有闲置的monitor(重量级锁对象),就会进行锁降级。

d4Hor9.jpg

为什么锁信息存放在对象头里

死磕Sunchronized底层实现--概论中:

因为在Java中任意对象都可以用作锁,因此必定要有一个映射关系,存储该对象以及其对应的锁信息(比如当前哪个线程持有锁,哪些线程在等待)。一种很直观的方法是,用一个全局map,来存储这个映射关系,但这样会有一些问题:需要对map做线程安全保障,不同的sunchronized之间会互相影响,性能差;另外当同步对象较多时,该map可能会占用比较多的内存。

所以最好的办法是将这个映射关系存储在对象头中,因为对象头本身也有一些hashcode、GC相关的数据,所以如果能将锁信息与这些信息共存在对象头中就好了。

也就是说,如果用一个全局map来存对象的锁信息,还需要对该map做线程安全处理,不同的锁之间会有影响,所以直接存到对象头。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栋幺栋幺-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值