【十三】一文带你了解下 synchronized 的实现原理

synchronized在JDK1.8中经历了从无锁、偏向锁、自旋锁到重量级锁的升级过程,旨在优化性能。偏向锁在无竞争时避免加锁,自旋锁则在竞争不激烈时减少阻塞。若锁持有时间过长,则升级为重量级锁,消耗更多资源。锁消除是编译阶段的优化,不必要的锁会被去除,而锁粗化则在频繁加解锁时将细粒度锁合并,以减少系统开销。
摘要由CSDN通过智能技术生成

synchronized具有以下特性(只考虑JDK1.8)

  • 开始是乐观锁,如果锁冲突频繁,就转换为悲观锁
  • 开始是轻量级锁,如果锁被持有时间的较长,就转换成重量级锁
  • 实现轻量级锁的时候大概率用到的自旋锁策略
  • 是一种不公平锁
  • 是一种可重入锁
  • 不是读写锁

1. synchronized的加锁过程

JVM 把 synchronized 锁分为 无锁、偏向锁、(自旋锁)轻量级锁、重量级锁。会根据情况,进行升级~
在这里插入图片描述

偏向锁

偏向锁,就是线程A针对锁,先进行一个标记,如果在整个代码执行过程中,没有其他线程和线程A竞争,此时就不用真的加锁~

自旋锁

当发生其他线程和线程A竞争的时候,就升级成了自旋锁,自旋锁是很快,但是消耗大量CPU资源
如果有10个线程竞争一把锁,1个竞争上,其他9个都得等待~此时就会消耗大量的CPU资源

重量级锁

面对上述情况,就升级成了重量级锁~在内核里进行阻塞等待(意味着放弃CPU资源,由内核进行后续调度)


对于主流的JVM的实现,只能升级,不能降级!

2. 锁的消除和锁的粗化

2.1 锁消除

非必要不加锁!上述升级是在程序运行时,JVM做出的优化
而锁消除,是编译阶段做的优化:检测当前代码是否是多线程执行/是否有必要加锁。如果没有必要,又把锁写了,就会在编译过程中自动把锁去掉

StringBuffer sb = new StringBuffer();
sb.append("a");
sb.append("b");
sb.append("c");

上述代码中,此时每个 append 的调用都会涉及加锁和解锁. 但如果只是在单线程中执行这个代码, 那么这些加锁解锁操作是没有必要的, 白白浪费了一些资源开销.

2.2 锁粗化

锁的粒度:synchronized 代码块,包含的代码多少(代码越多,粒度越粗,代码越少,粒度越细)
一般写代码的时候,多数情况下,是希望锁的粒度更细一点(串行执行的代码少,并发执行的代码就多)


但是有一个场景,要频繁加锁、解锁,此时编译器就可能把这个操作优化成一个更粗粒度的锁
在这里插入图片描述

  • 实际开发过程中, 使用细粒度锁, 是期望释放锁的时候其他线程能使用锁.
  • 但是实际上可能并没有其他线程来抢占这个锁. 这种情况 JVM 就会自动把锁粗化, 避免频繁申请释放锁.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个想打拳的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值