csworkman

个人博客

Synchronized与锁升级

2022-6-16 Mr Chang JUC

  1. Synchronized 锁优化的背景
    用锁能够实现数据的安全性,但是会带来性能下降。无锁能够基于线程并行提升程序性能,但是会带来安全性下降。
    求平衡???
  2. 升级流程
    Synchronized用的锁是存在Java对象头里的Mark Word中
    锁升级功能主要依赖于MarkWord中锁标志位和释放偏向锁标志位
  3. 锁指向,请牢记
    偏向锁:MarkWord存储的是偏向的线程ID;
    轻量锁:MarkWord存储的是指向线程栈中Lock Record的指针;
    重量锁:MarkWord存储的是指向堆中的monitor对象的指针;

无锁:
初始状态,一个对象被实例化后,如果没有被任何线程竞争锁,那么它就为无锁状态(001)

偏向锁:
单线程竞争
注意:偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程是不会主动释放偏向锁的。
在没有其他线程竞争的时候,一直偏向偏心当前线程,当前线程可以一直执行。偏向于第一个获得它的线程。执行完同步代码块后,线程并不会主动释放偏向锁。

题外话  Java15 逐步废弃偏向锁 默认在虚拟机当中不再开启
重点课程对应 谷粒学院JUC 课时130


轻量级锁:
  1. 主要作用:有线程来参与锁的竞争,但是获取锁的冲突时间极短,本质就是自旋锁CAS
  2. 获取:如果关闭偏向锁,则自动升级为轻量级锁
  3. 如果轻量级锁在自旋达到一定次数仍然不能成功,则升级为重量级锁。
  4. 自适应自旋的大致原理
    线程如果自旋成功了,那下次自旋的最大次数增加,因为JVM认为既然上次成功了,那么这一次也很大概率成功。
    反之,如果很少会自旋成功,那么下次会减少自旋的次数甚至不自旋,避免CPU空转。
轻量锁和偏向锁的区别和不同:
  1. 争夺轻量级锁失败时,自旋尝试抢占锁
  2. 轻量级锁每次退出同步块都需要释放锁,而偏向锁是在竞争发生时才释放锁
重量级锁 ————指向互斥量(重量级锁)的指针

重量级锁原理
Java中synchronized的重量级锁,是基于进入和退出Monitor对象实现的。在编译时会将同步块的开始位置插入monitor enter 命令,在结束位置插入monitor exit 指令

当线程执行到monitor enter指令时,会尝试获取对象所对应的Monitor所有权,如果获取到了,即获取到了锁,会在Monitor的owner中存放当前线程的id, 这样它将处于锁定状态,除非退出同步块,否则其他线程无法获取到这个Monitor。

JDK1.6之后进行了优化,拥有了无锁->偏向锁->轻量级锁->重量级锁的升级过程,而不是无论什么情况都使用重量级锁。

发表评论: