Synchronized锁膨胀机制

前言

最近在读《深入理解JVM》,读到第13章 线程安全与锁优化中的轻量级锁与偏向锁时,总是难以理解,直到读到了这篇 死磕Synchronized底层实现–概论后,才恍然大悟,逐渐理解了书中的内容,特此来记录一下。

锁膨胀流程

被Synchronized修饰的方法/代码块,根据争抢线程的数量,时机不同,会经历以下的过程

无锁
偏向锁
轻量级锁
重量级锁

大家先了解有这么一个流程,下面来逐个解读

一个对象怎样才算获得了锁

既然每个对象都有可能获取到锁资源,那么怎样才能知道是哪个对象获取到了锁呢?
在Java中,是通过修改对象头(对象的组成部分之一,存储了对象的运行时数据,哈希码等信息)中的信息来标记该对象是否取得了锁资源的。

对象头的数据结构

偏向锁

偏向锁,顾名思义,它会偏向第一个获取到它的线程,在接下来的执行过程中,如果没有没有其他线程来获取锁资源,那么该线程再次来获得锁资源时则不需要进行同步。

加锁过程

当某个锁第一次被一个线程获取时,就会加偏向锁。加锁逻辑是首先将对象头中的标记为设置成01,然后把获取到这个锁的线程id记录到对象头中。这就表示该线程获取了偏向锁。

解锁过程

偏向锁的解锁条件很简单,在一个线程获得了偏向锁后,只要有另一个线程来尝试获取锁,并且当前持有偏向锁的线程仍存活,偏向锁就立马解除,锁膨胀为轻量级锁。

轻量级锁

加锁过程

当一个对象的代码即将进入同步块时,首先会判断该同步对象是否已经锁定,若未锁定,则说明该锁资源空闲。JVM会现在栈中创建一个锁记录,来记录获取到了锁的对象。该锁记录里会存放获取了锁资源的对象的对象投中的部分信息。创建完锁记录之后,JVM将使用CAS操作来更新对象的对象头信息,尝试将锁记录的指针放入对象头中,并修改其标志位。

  • 如果这个操作成功,则说明该对象获取到了锁资源并进入轻量级锁状态。
  • 如果失败了则说明至少有一条线程与当前线程竞争获取该锁资源。此时虚拟机检查当前对象头是否有指向栈帧中锁记录的指针。 若有,则说明当前是当前对象得到了锁资源(此处注意线程与对象的关系),直接进入同步块执行即可。否则则说明锁已经被其他对象的线程抢占。此时就需要膨胀为重量级锁

解锁过程

解锁过程同样也是通过CAS来进行的。具体操作是用CAS操作用当前对象头中的信息来替换锁记录中保存的信息,若成功(在锁记录仍指向该对象的对象头信息时才能成功),则释放锁。如果失败了,则说明有其他对象来获取过该锁,在释放锁的同时,还要唤起被挂起的线程。

重量级锁

重量级锁不必多说,就是大家通常了解的的Synchronized的加锁,解锁过程。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值