当前位置: 首页 > article >正文

Synchronized原理

目录

一.Synchronized锁的状态

二.偏向锁

1.加锁过程

2.解锁过程

三.轻量级锁

1.加锁过程

2.解锁过程

四.重量级锁

五.总结


一.Synchronized锁的状态

四种锁状态:

        1.无锁

        2.偏向锁

        3.轻量级锁

        4.重量级锁

锁的级别由低到高分别是:无锁状态->偏向锁状态->轻量级锁状态->重量级锁状态。这几个状态会随着锁的竞争情况逐渐升级(只能升级,不能降级),也叫锁的膨胀。

二.偏向锁

作用:减少同一线程获取锁的代价

        偏向锁假定将来只有第一个申请锁的线程会使用锁(不会有任何线程再来申请锁),因此,只需要在Mark Word中CAS记录owner(本质上也是更新,但初始值为空),如果记录成功,则偏向锁获取成功,记录锁状态为偏向锁,以后当前线程等于owner就可以零成本的直接获得锁;否则,说明有其他线程竞争,膨胀为轻量级锁。

1.加锁过程

        当锁对象第一次被线程获取的时候,虚拟机把对象头中的锁标志位设为“01”,即偏向模式。同时使用CAS操作把获取到这个锁的线程的ID记录在对象的Mark Word之中的偏向线程ID,并将是否偏向锁的状态位置置为1。如果CAS操作成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时,直接检查markword中的ThreadId是否和 自身线程Id一致,如果一致,则认为当前线程已经获取了锁,JVM就可以不再进行任何同步操作。

        当有另外一个线程去尝试获取这个锁时,偏向模式就宣告结束。根据锁对象目前是否处于被锁定的状态,撤销偏向(Revoke Bias)后恢复到未锁定状态或 轻量级锁定(标志位为“00”)的状态。

2.解锁过程

        一旦有第二个线程访问这个对象,因为偏向锁不会主动释放,所以第二个线程可以看到对象是偏向状态,这时表明在这个对象上已经存在竞争了,检查原来持有该对象锁的线程是否依然存活,如果挂了,则可以将对象变为无锁状态,然后重新偏向新的线程,如果原来的线程依然存活,则马上执行那个线程的操作栈,检查该对象(锁)的使用情况,如果仍然需要持有偏向锁,则偏向锁升级为轻量级锁,(偏向锁就是这个时候升级为轻量级锁的)。如果不存在使用了,则可以将对象(锁)回复成无锁状态,然后重新偏向。

三.轻量级锁

        当有别的线程参与到偏向锁的竞争中时,会先判断 markword 中的线程ID与这个线程是否一致,如果不一致,则会立即撤销偏向锁,升级为轻量级锁。

        每个线程都会在自己的栈中维护一个 LockRecord(LR),然后每个线程在竞争锁时,都试图将 锁对象头 中的markword 设置为指向自己LR的指针,哪个线程设置成功,则意味着哪个线程成功获取到锁。

1.加锁过程

        在代码进入同步块前,如果该同步块没有被锁定(即锁的标志位为“01”),那么JVM在将当前线程的栈帧中,创建一个 LockRecord(锁记录LR),并将锁对象头中的 markWord 信息复制到锁记录(LR)中,这个官方称为 Displaced Mard Word。
然后线程尝试使用 CAS 将对象头中的 MarkWord 替换为指向锁记录(LR)的指针。

如果这个更新动作成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位(Mark Word的最后2bit)将转变为“00”,即表示此对象处于轻量级锁定状态。

如果 cas 失败,有两种情况:
        如果是其它线程已经持有了该 Object 的轻量级锁,这时表明有竞争,当前线程便尝试使用自旋来获取锁。如果在自旋一定次数后仍未获得锁,那么轻量级锁将会升级成重量级锁。
        如果是自己执行了 synchronized 锁重入,那么再添加一条 Lock Record 作为重入的计数

2.解锁过程

        当退出 synchronized 代码块(解锁时)如果有取值为 null 的锁记录,表示有重入,这时重置锁记录,表示重入计数减一。
        当退出 synchronized 代码块(解锁时)锁记录的值不为 null ,这时使用 cas Mark Word 的值恢复给对象头。
        成功,则解锁成功
        失败,说明轻量级锁进行了锁膨胀或已经升级为重量级锁,进入重量级锁解锁流程

四.重量级锁

        如果在尝试加轻量级锁的过程中,CAS 操作无法成功,这时一种情况就是有其它线程为此对象加上了轻量级锁(有竞争),这时需要进行锁膨胀,将轻量级锁变为重量级锁。
这时 Thread-1 加轻量级锁失败,进入锁膨胀流程:
        即为 Object 对象申请 Monitor 锁,让 Object 指向重量级锁地址
        然后自己进入 Monitor EntryList BLOCKED
        当 Thread-0 退出同步块解锁时,使用 cas Mark Word 的值恢复给对象头,失败。这时会进入重量级解锁流程,即按照 Monitor 地址找到 Monitor 对象,设置 Owner null ,唤醒 EntryList BLOCKED 线程。

五.总结

由于轻量级锁会自旋,即不会放弃CPU,那么对一些执行时间短的任务而言,用轻量级锁可以减少线程切换的时间(对比重量级锁)。

(1)偏向锁通过对比 Mark Word 解决加锁问题,避免执行CAS操作。
(2)轻量级锁是通过用 CAS 操作和自旋来解决加锁问题,避免线程阻塞和唤醒而影响性能。
(3)重量级锁是将除了拥有锁的线程以外的线程都阻塞。


http://www.kler.cn/a/398284.html

相关文章:

  • 基于gradio+networkx库对图结构进行可视化展示
  • 30-集群Backup Restore
  • MySQL数据库:SQL语言入门 【3】(学习笔记)
  • 通过JS删除当前域名中的全部COOKIE教程
  • git创建远程仓库,以gitee码云为例GitHub同理
  • 深入探索 Kubernetes 安全容器:Kata Containers 与 gVisor
  • K8S单节点部署及集群部署
  • PyTorch 张量的常用 API
  • Guava Cache
  • SQLI LABS | Less-51 GET-Error Based-ORDER BY CLAUSE-String-Stacked Injectiion
  • 图像分割——Hough变换检测法
  • C语言——判断是不是字母
  • YOLOv7-0.1部分代码阅读笔记-train.py
  • SQLite 安装指南
  • MAC上的Office三件套报53错误解决方案(随笔记)
  • 【MogDB】MogDB5.2.0重磅发布第八篇-支持PLSQL编译全局缓存
  • 如何在 Ubuntu 上安装 Mattermost 团队协作工具
  • 【ArcGIS微课1000例】0127:计算城市之间的距离
  • 9.2 使用haarcascade_frontalface_default.xml分类器检测视频中的人脸,并框出人脸位置。
  • 企业项目级IDEA设置类注释、方法注释模板(仅增加@author和@date)
  • 你的服务器缓存中毒过么?
  • Essential Cell Biology--Fifth Edition--Chapter one (8)
  • ssm126基于HTML5的出租车管理系统+jsp(论文+源码)_kaic
  • 牛客周赛第一题2024/11/17日
  • 深入理解Flutter生命周期函数之StatefulWidget(一)
  • 【Qt聊天室】客户端实现总结