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

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(十九)- JUC(5)

synchronized优化原理

轻量级锁

如果一个对象有多个线程访问,但多线程访问的时间是错开的(没有竞争),可以用轻量级锁优化

  @Slf4j(topic = "c.ExerciseTransfer")public class Test {​static final Object obj = new Object();public static void main(String[] args) throws InterruptedException {synchronized (obj){method();}}​public static void method(){synchronized (obj){}}}

让锁记录中 Object reference 指向锁对象,并尝试用 cas 替换 Object 的 Mark Word,将 Mark Word 的值存 入锁记录

如果 cas 替换成功,对象头中存储了 锁记录地址和状态 00 ,表示由该线程给对象加锁,这时图示如下。

如果 cas 失败,有两种情况

  • 如果是其它线程已经持有了该 Object 的轻量级锁,这时表明有竞争,进入锁膨胀过程

  • 如果是自己执行了 synchronized 锁重入,那么再添加一条 Lock Record 作为重入的计数

当退出 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 线程。

自旋优化

重量级锁竞争的时候,还可以使用自旋来进行优化,如果当前线程自旋成功(即这时候持锁线程已经退出了同步块,释放了锁),这时当前线程就可以避免阻塞。

偏向锁

轻量级锁在没有竞争时(就自己这个线程),每次重入仍然需要执行 CAS 操作。

Java 6 中引入了偏向锁来做进一步优化:只有第一次使用 CAS 将线程 ID 设置到对象的 Mark Word 头,之后发现这个线程 ID 是自己的就表示没有竞争,不用重新 CAS。以后只要不发生竞争,这个对象就归该线程所有。例如:

  static final Object obj = new Object();public static void m1() {synchronized( obj ) {// 同步块 Am2();}}public static void m2() {synchronized( obj ) {// 同步块 Bm3();}}public static void m3() {synchronized( obj ) {// 同步块 C}}

偏向状态

之所以要用偏向锁是因为轻量级锁的锁重入每次都调用CAS进行对比,CAS是一个OS指令操作,速度很慢。所以偏向锁是把ThreadId直接赋值给markword,那么下次能直接在java上对比这个markword。

  1. 偏向锁带有延迟性,通常对象创建过一会才会生成

  2. 先生成偏向锁->轻量级锁->重量级锁

  3. 如果给临时区使用偏向锁,那么对应执行线程的id赋值给markword

  4. 如果使用了锁的hashcode,那么偏向锁就会被禁止,因为hashcode占用的bit太多。

  5. 轻量级在锁记录上记录hashcode,重量级在monitor上记录

  6. 如果两个线程用同一个偏向级锁,那么锁会变成不可偏向,升级为轻量级锁。

相关文章:

  • 在Visual Studio Code和Visual Studio 2022下配置Clang-Format,格式化成Google C++ Style
  • linux的用户管理
  • 前端 MVC 分层的实践
  • 公司废弃的2014年群晖 DS215J 被我打包回家了,试玩一下
  • 世界上首位AI程序员诞生,AI将成为人类的对手吗?
  • Vue.js - Vue 的安装 以及 常用的 Vue 指令 【0基础向 Vue 基础学习】
  • Pytorch-08 实战:手写数字识别
  • 力扣刷题---3146. 两个字符串的排列差
  • 开源内网穿透神器:中微子代理(neutrino-proxy)实现内网穿刺
  • python毕设项目选题汇总(全)
  • 27寸2K显示器 - HKC G27H2
  • ELK 日志监控平台(一)- 快速搭建
  • springboot 两个相同类型的Bean使用@Resouce加载
  • 数据库工具类
  • CHI dataless 传输——CHI(4)
  • [ JavaScript ] 数据结构与算法 —— 链表
  • Angular 响应式表单 基础例子
  • Angularjs之国际化
  • Apache Zeppelin在Apache Trafodion上的可视化
  • co.js - 让异步代码同步化
  • express + mock 让前后台并行开发
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • Java的Interrupt与线程中断
  • learning koa2.x
  • Next.js之基础概念(二)
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • Transformer-XL: Unleashing the Potential of Attention Models
  • Vue.js源码(2):初探List Rendering
  • Vultr 教程目录
  • zookeeper系列(七)实战分布式命名服务
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 对话 CTO〡听神策数据 CTO 曹犟描绘数据分析行业的无限可能
  • 构造函数(constructor)与原型链(prototype)关系
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 思维导图—你不知道的JavaScript中卷
  • 线上 python http server profile 实践
  • 一道面试题引发的“血案”
  • 用简单代码看卷积组块发展
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • RDS-Mysql 物理备份恢复到本地数据库上
  • 策略 : 一文教你成为人工智能(AI)领域专家
  • 正则表达式-基础知识Review
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ​探讨元宇宙和VR虚拟现实之间的区别​
  • #70结构体案例1(导师,学生,成绩)
  • #Lua:Lua调用C++生成的DLL库
  • #pragma once
  • #数学建模# 线性规划问题的Matlab求解
  • (1)安装hadoop之虚拟机准备(配置IP与主机名)
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (done) ROC曲线 和 AUC值 分别是什么?
  • (LeetCode 49)Anagrams
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血