聊一聊synchronized锁的状态与升级


一、简介

java在1.6之后为了减少获得锁和释放锁带来的性能消耗,引入了偏向锁和轻量级锁的概念,在jdk 1.6中,锁分为四种状态,从低到高为:无锁,偏向锁,轻量级锁,重量级锁。这几个状态会随着线程竞争不断升级,但是升级后的状态不会再降级。

二、对象头

在介绍锁的状态升级之前,我们先了解一下,java对象头的基本概念。

java对象头分为三个部分:

  1. Mark Word
  2. 对象数据的指针
  3. 数组对象的长度(如果是数组的话)

synchronized用的锁是存在Java对象头的Mark Word里。我们这里主要看看Mark Word里面不同锁状态下存储的是什么。
在这里插入图片描述

从上面的图中,有一个分代年龄,GC回收的年龄为什么默认是15 ,因为在Mark Word中分代年龄只有4bit,而4bit最大也只能是15

三、锁的状态

无锁:是最理想的状态,线程无须任何竞争便可以直接访问同步代码块的内容。

偏向锁:偏向于第一个访问的线程。

在这里插入图片描述

  1. 线程A访问同步快,判断对象头Mark Word 里的锁标识是否为偏向锁。是走2,不是走3。
  2. 检查Mark Word里的线程id是不是指向当前线程,如果是走4,不是走3。
  3. CAS操作替换Mark Word线程id指向当前线程,成功走4,不成功走5.
  4. 获得偏向锁,执行同步代码块的内容。
  5. 开始执行偏向锁的撤销,等待原持有偏向锁的线程到达安全点,暂停当前线程,检查原持有偏向锁线程的线程状态。线程状态不是活动或 者已经退出同步代码块走6,否则走7。
  6. 原持有线程开始释放锁,修改Mark Word 里的线程id为空,唤醒暂停线程,继续按1的步骤开始走下去。
  7. 锁膨胀,开始升级为轻量级锁。

轻量级锁:本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。

在这里插入图片描述

  1. 线程访问同步块,检查锁的状态是否01,是走上面的偏向锁流程,不是走第二步。
  2. 线程栈中分配Lock Record空间,复制对象头的Mark Word 到线程锁记录里,官方名词 Displaced Mark Word 。
  3. CAS替换对象头Mark Word的锁记录指针指向到线程栈中新分配的锁记录,替换成功走5,不成功走4。
  4. 自旋,循环执行3,当自旋达到一定次数时,仍然没有获取成功,锁开始升级成为重量级锁,当前线程挂起。
  5. 线程获取轻量级锁成功,开始执行同步代码块内容。
  6. 同步代码块内容执行完毕,开始释放轻量级锁。
  7. CAS操作,将线程栈中的 Displaced Mark Word 替换回对象头的Mark Word,替换成功则直接释放锁。替换失败则释放锁并且唤醒暂停的线程。

相比较偏向锁,轻量级锁多了一个 Displaced Mark Word 的动作,在线程栈中复制原对象的Mark Word ,在使用完之后在替换回去。

为什么轻量级锁在释放锁的时候,在CAS操作替换失败之后,要唤醒暂停的线程?

CAS操作失败,说明对象头的Mark Word 已经被改变,当前对象可能有多个线程在竞争,只有在替换锁标识的时候,对象头的Mark Word才可能被改变,这时已经是轻量级锁,不可能降级,所以锁已经升级成重量级锁,其他竞争的线程已经被挂起。释放锁的线程需要唤醒其他被挂起的线程,让他们继续竞争。

重量级锁: 理论上,无锁,偏向锁,和轻量级锁都是乐观锁,设计的本意是倾向于无竞争,或者竞争很小的情况下使用,用来减少重量级锁使用操作系统频繁切换内核态的性能损耗,当锁的竞争加剧的时候,乐观锁并不能带来足够的性能提升,相反可能回导致资源消耗加大,这时,锁的状态就会直接升级成重量级锁。

结合偏向锁和轻量级锁的升级和撤销过程,下图是锁在几个状态如何撤销升级的流程。

在这里插入图片描述
线程在访问同步块的时候,判断锁的状态:

  1. 锁标识是01的时候,直接走偏向锁的链路。
  2. 锁标识是00 的时候,直接走轻量级锁的链路。
  3. 锁标识是10的时候,直接走重量级锁的链路,挂起线程。

关于轻量级锁如何膨胀到重量级锁

  1. 自旋到一定次数(使用-XX:+UseSpinning参数来开启,在JDK 1.6中就已经改为默认开启了。自旋次数的默认值是10次,用户可以使用参数-XX:PreBlockSpin来更改。),
  2. 在自旋时,有第三个线程来竞争。
  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值