synchronized 锁分级

 

说明    

    在JDK 1.8中,synchronized 的速度已经有了显著的提升,主要通过分级锁的方式。JVM 会根据使用情况对synchronized锁升级,会如此路径升级:偏向锁 -->轻量级锁--> 重量级锁。

锁信息

    那锁是通过什么方式判断锁是否要升级呢?关键信息在对象头里,对象分为MarkWord、Class Pointer、Instance Data、Padding,其中MarkWord跟锁信息有关,它的长度是 24 位,它包含Thread ID(23bit)、Age(6bit)、Biased(1bit)、Tag(2bit) 四个部分,锁升级就是靠 Thread Id、Biased、Tag 等变量值来进行判断


分级类型

偏向锁

    在只有一个线程使用了锁的情况下,偏向锁能够保证更高的效率。具体过程是这样的:

1)当第一个线程第一次访问同步块时,会先检测对象头 Mark Word 中的标志位 Tag 是否为 01,以此判断此时对象锁是否处于无锁状态或者偏向锁状态(匿名偏向锁)。

2)01是锁默认的状态,线程一旦获取了这把锁,就会把自己的线程ID写到MarkWord 中,在其他线程来获取这把锁之前,锁都处于偏向锁状态。

3)当下一个线程参与到偏向锁竞争时,会先判断 MarkWord 中保存的线程ID是否与这个线程 ID 相等,如果不相等就会立即撤销偏向锁,升级为轻量级锁。

 

轻量级锁

轻量级锁的获取是通过自旋方式。参与竞争的每个线程,会在自己的线程栈中生成一个 LockRecord ( LR ),然后每个线程通过 CAS(自旋)的方式,将锁对象头中的 MarkWord 设置为指向自己的 LR 的指针,哪个线程设置成功,就意味着哪个线程获得锁。当锁处于轻量级锁的状态时,就不能够再通过简单地对比 Tag 的值进行判断,每次对锁的获取,都需要通过自旋。当然,自旋也是面向不存在锁竞争的场景,比如一个线程运行完了,另外一个线程去获取这把锁;但如果自旋失败达到一定的次数,锁就会膨胀为重量级锁。

 

重量级锁

    重量级锁,线程会挂起,进入到操作系统内核态,等待操作系统的调度,然后再映射回用户态。系统调用是昂贵的,所以重量级锁的名称由此而来。如果系统的共享变量竞争非常激烈,锁会迅速膨胀到重量级锁,这些优化就名存实亡。如果并发非常严重,可以通过参数 -XX:-UseBiasedLocking 禁用偏向锁,理论上会有一些性能提升,但实际上并不确定。

 

锁只能升级,不能降级

参考资料:拉钩《Java 性能优化实战 21 讲》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值