Java中synchronized的工作原理

“锁膨胀” 的过程~

场景:多个线程尝试i++,假设这些线程不是同时运行的。

1)第一个线程开始i++,就需要先加锁~
但是第一个线程首次加锁,不是进行真加锁,而只是在对象头里通过一个特殊标志位,标记一下(某个线程想要获取到锁),这里由于是一个线程进行操作,所以还不涉及到线程问题,所以只是标记一下。这个线程赌后面没有其他线程来竞争这个锁!!这也是一个乐观锁。
同时这不是一个真的加锁,而只是标记了一下,所以我们也叫作偏向锁

2)当第一个线程以偏向锁的状态进行i++的过程中,第二个线程也来尝试竞争锁~~

这个时候第二个线程也来竞争锁,第一个线程立马不乐意了,锁竞争真的发生了,于是第一个线程就会立即获取到锁状态~~ 第二个线程也会真加锁,就真正涉及到了锁竞争~~

举个例子:
就比如张三,在追妹子的时候,已经和妹子关系很好了,但是只是搞暧昧,并没有明确关系,突然李四来了,也向妹子发起追求,此时张三就坐不住了,立马和妹子表态,确认男女朋友关系,然后李四就竞争失败,变成备胎,继续等~~

上面说的立刻获取到锁状态,是使用轻量级锁来加锁的~,第二个线程也是通过轻量级锁来加锁 ~

就从 偏向锁 到 轻量级锁 就有一个从轻到重的过程,就叫做“锁膨胀”,锁的量级从轻到重~

3)接下来,其他线程接二连三的过来竞争,i++操作的锁竞争越来越激烈,轻量级锁虽然快,也不是那么容易获取到锁了,吃的CPU也变多了;

此时这些持有轻量级锁的线程,就要在进一步膨胀成‘重量级锁’ mutex,然后获取到锁的线程继续工作,没有获取到锁得线程就进入内核态,阻塞等待…就变成了 重量级锁!!

这整个锁策略自动切换的过程,称为“锁膨胀” / “锁升级” ,都是由synchronized内部完成的(也就是JVM内部来完成的)

目的就是为了,在不同场景下,使用不同的锁~~ 提高效率!!

偏向锁 -》 轻量级锁 -》重量级锁,这样一个过程是synchronized 的 自适应 完成的~,根据锁竞争的激烈程度 ~

synchronized 的一些其他优化手段

优化是编译器 + JVM共同配合完成的工作~ 设计编译器和JVM的大佬们,就希望达到,代码你随便写…我给你优化!!

1. 锁消除

如果某个代码 编译器/ JVM 判定不涉及线程安全问题,就会自动把程序猿加的锁去掉~~

举个例子: StringBuilder 和 StringBuffer

在这里插入图片描述
但是如果是单线程下,直接使用StringBuffer,其实就会涉及到一些无意义的加锁操作,虽然有锁的自适应,但是自适应并不是等于 0,也还是有开销的,所以我们还是希望,让他能不做,就尽量不做~

这个时候,锁消除就起到效果了。编译器就会判断,针对StringBuffer的操作是否都是在一个线程内完成的,如果是,就不再真的加锁。而是在编译生成字节码里就把加锁操作给去掉了~

2.锁的粗化

就好比StringBuffer 添加元素的时候~

StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("bbb");
        stringBuffer.append("bbb");
        stringBuffer.append("bbb");
        stringBuffer.append("bbb");

上述代码中,每个append 都会加锁,解锁~

假设这里确实是多线程操作StringBuffer,不能消除锁了~

这里就涉及到一个问题 锁的‘粒度’,指的就是synchronized影响到代码的范围~
在这里插入图片描述

所谓的对锁进行粗化,就是把这种连续的加锁解锁操作,合并成一次加锁解锁(锁的粒度变大了)

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值