吃透Java并发:一文看懂锁升级流程

前言

在对synchronized的轻量级锁、重量级锁介绍中其实已经对该流程有所讲解,不过不够明朗
本章旨在让大家能够了解,jdk1.6之后synchronized升级的完整流程


1、无锁

无锁状态肯定是最好理解的了,比如说下面这一段代码:

public void test(){
    a = b + c;
}

无论是线程A还是线程B来访问都不会有任何锁,平平无奇。

2、无锁 -> 偏向锁

假如我们为这段代码加上了synchronized

public void test(){
        synchronized (object) {
            a = b + c;
        }
    }

此时只有线程A来访问这段代码,此时object对象头中的MarkWord还是自己的,于是线程A很轻松就把object中的MarkWord通过CAS进行对换:

对换成功之后,此时object中的MarkWord变成了线程A Lock record的MarkWord。

但是要知道,synchronized是可以重入的,假如线程A又要访问这段代码,JVM又执行了一遍上述流程。一次两次。。。一百次,每次都要进行CAS,但是每次只有线程A使用。

于是对此JVM做了一个小小的优化:如果在重入到一定阈值之后仍然没有任何线程抢占行为发生,JVM就会省略CAS这个操作,以后只要不发生竞争,这个对象就归该线程所有

3、偏向锁 -> 轻量级锁

同样是之前那段代码,假如这时候线程B也参和进来,但是此时临界资源object是被线程A持有,于是这时候线程B没办法进入临界区,怎么办?

3.1 自旋优化

直接阻塞或者进行上下文切换是十分耗费性能的做法,因为涉及到用户态和内核态的切换,JVM很明显不会这么笨,在这里做了另一个优化:

如果线程B发现临界资源被占用,不会立即放弃CPU使用权,而是在这期间进行自旋尝试对object进行CAS。

因为一般来说,临界资源是不会被占用很久的,做这个优化的意思就是说,反正闲着也是闲着,说不定等一会别人就用完把锁还回来了呢?

3.2 偏向锁撤销

假如这时候线程A使用完object进行归还之后,线程B进行临界资源的抢占。此时无论线程B抢占成功与否,JVM在发现抢占行为这个动作之后,会把object上的偏向锁标志位清除,取而代之的是升级为轻量级锁。

4、轻量级锁 -> 重量级锁

升级为轻量级锁之后,假如此时object被线程B持有,线程A再来尝试获取object时,同样会进行自旋尝试。

但是这个自旋不会一直持续下去,当JVM发现线程B自旋一定次数或者还有线程C来插足时,这时候就会申请monitor对象。

而这个monitor对象才是真正的重量级锁。具体可以参考synchronized的原理和轻量级、重量级以及偏向锁

结尾

synchronized的性能在这些优化下已经很优秀,但是面临一些场景还是无法灵活应付。
对此J.U.C家族下提供的大量并发工具类就可以派上用场了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值