Synchronized锁升级过程

本文详细介绍了Java中Synchronized锁的升级过程,从无锁到偏向锁、轻量级锁,再到重量级锁。在无锁状态下,对象头包含对象哈希码等信息。当出现锁竞争时,转变为偏向锁,线程通过CAS操作尝试加锁。如果多线程竞争激烈,锁会升级为轻量级锁,采用自旋和CAS避免阻塞。当自旋失败,锁进一步升级为重量级锁,涉及操作系统Mutex Lock,切换成本高。整个过程中,锁的状态通过对象头信息进行管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Synchronized锁升级过程:无锁 -> 偏向锁(CAS) -> 轻量级锁 (CAS,自适应自旋) -> 重量级锁 (悲观锁)

对象头信息

Synchronized锁对象,在对象头中标注锁信息,每一行是一种状态,对象只能有一种状态,通过锁标志位判断。
在这里插入图片描述

无锁

无锁状态:对象头25bit存对象hashcode,4bit存分代年龄,1bit存偏向锁(0),2bit存锁标志位(01)。顶图中第五行数据。

偏向锁

现在ThreadA和ThreadB线程一起抢锁,过程如下:
在这里插入图片描述

  • 首先判断对象是否有锁,无锁进行CAS加锁。
    这时候ThreadA和ThreadB进行抢锁,如ThreadA抢锁成功,会修改对象头信息:把ThreadId设置成自己,Epoch代表偏向时间戳,对象变化如下:

在这里插入图片描述
此时锁偏向ThreadA,如果ThreadA再次抢锁那么,会检查ThreadId是否是自己,如果是自己直接加锁,无需CAS,如果不是说明发现锁竞争。

偏向锁:指的就是偏向第一个加锁ThreadA,该线程是不会主动释放偏向锁的,只有当其他ThreadB尝试竞争偏向锁才会被释放。

偏向锁释放

其实就是ThreadB要操作的时候,看是否可以释放掉ThreadA的偏向锁。需要等待全局安全点(在这个时间点上没有正在执行的字节码),它会首先暂停拥有偏向锁的ThreadA(达到全局安全点再暂停),然后检查持有偏向锁的ThreadA是否还活着:

  • 如果ThreadA不处于活动状态,则将锁对象的MarkWord设置成无锁状态,(再指向ThreadB)。
  • 如果ThreadA仍然活着,拥有偏向锁a的栈会被执行。
    • 当线ThreadA不需要用到该偏向锁了,则恢复到无锁,(再指向ThreadB)。
    • 如果ThreadA还要用,则和ThreadB产生竞争,标记对象不适合作为偏向锁。最后唤醒暂停的线程。

在这里插入图片描述

轻量级锁

如果ThreadB没有拿到锁,我们就会升级到轻量级锁,首先会在ThreadA和ThreadB都开辟一块LockRecord空间,然后把锁对象复制一份到自己的LockRecord空间下,并且开辟一块owner空间留作执行锁使用,并且锁对象的前30bit位合并,等待ThreadA和ThreadB来修改指向自己的线程,假如ThreadA修改成功,则锁对象头的前30bit位会存ThreadA的LockRecord的内存地址,并且ThreadA的owner也会存一份锁对象的内存地址,形成一个双向指向的形式。而ThreadB修改失败,则进入一个自旋状态,就是持续来修改锁对象。

在这里插入图片描述

重量级锁

如果说ThreadB多次自旋以后还是迟迟没有拿到锁,他会继续上告,告知虚拟机,我多次自旋还是没有拿到锁,这时我们的ThreadB会由用户态切换到内核态,申请一个互斥量,并且将锁对象的前30bit指向我们的互斥量地址,并且进入睡眠状态,然后我们的ThreadA继续运行知道完成时,当ThreadA想要释放锁资源时,发现原来锁的前30bit位并不是指向自己了,这时ThreadA释放锁,并且去唤醒那些处于睡眠状态的线程,锁升级到重量级锁。

在这里插入图片描述
重量级锁通过对象内部的监视器(monitor)实现,而其中 monitor 的本质是依赖于底层操作系统的 Mutex Lock 实现,操作系统实现线程之间的切换需要从用户态切换到内核态,切换成本非常高。

重量级锁维护了一个队列:
在这里插入图片描述

  • Entry Set:待获得锁的线程
  • The Owner:已获得锁的线程
  • Wait Set:等待队列(调用wait方法)

当一个线程释放监视器时,在入口区和等待区的等待线程都会去竞争监视器,如果入口区的线程赢了,会从2号门进入;如果等待区的线程赢了会从4号门进入。只有通过3号门才能进入等待区,在等待区中的线程只有通过4号门才能退出等待区,也就是说一个线程只有在持有监视器时才能执行wait操作,处于等待的线程只有再次获得监视器才能退出等待状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值