cas 和 synchronized 优化过程

cas

什么是CAS

 CAS:全称Compareandswap,字⾯意思:”⽐较并交换“,⼀个CAS涉及到以下操作: 我们假设内存中的原数据V,旧的预期值A,需要修改的新值B。

 1. ⽐较A与V是否相等。(⽐较) 

2. 如果⽐较相等,将B写⼊V。(交换)

 3. 返回操作是否成功。

CAS伪代码 

下⾯写的代码不是原⼦的,真实的CAS是⼀个原⼦的硬件指令完成的.这个伪代码只是辅助理解CAS的⼯作流程.

boolean CAS(address, expectValue, swapValue) {if (&address == expectedValue) {&address = swapValue;return true;}return false;
}

CAS有哪些应用

1)实现原⼦类 

标准库中提供了ava.util.concurrent.atomic 包,⾥⾯的类都是基于这种⽅式来实现的. 典型的就是AtomicInteger类.其中的getAndIncrement相当于i++操作.

AtomicInteger atomicInteger = new AtomicInteger(0);
// 相当于 i++ 
atomicInteger.getAndIncrement();

伪代码实现:

class AtomicInteger {private int value;public int getAndIncrement() {int oldValue = value;while ( CAS(value, oldValue, oldValue+1) != true) {oldValue = value;}return oldValue;}
}

假设两个线程同时调⽤getAndIncrement 

1. 两个线程都读取value的值到oldValue中.(oldValue是⼀个局部变量,在栈上.每个线程有⾃⼰的栈)

2. 线程1先执⾏CAS操作.由于oldValue和value的值相同,直接进⾏对value赋值.

 注意:

 • CAS是直接读写内存的,⽽不是操作寄存器.

 • CAS的读内存,⽐较,写内存操作是⼀条硬件指令,是原⼦的.

3. 线程2再执⾏CAS操作,第⼀次CAS的时候发现oldValue和value不相等,不能进⾏赋值.因此需要 进⼊循环.

 在循环⾥重新读取value的值赋给oldValue

4. 线程2接下来第⼆次执⾏CAS,此时oldValue和value相同,于是直接执⾏赋值操作.

5. 线程1和线程2返回各⾃的oldValue的值即可.

 通过形如上述代码就可以实现⼀个原⼦类.不需要使⽤重量级锁,就可以⾼效的完成多线程的⾃增操作. 

本来checkandset这样的操作在代码⻆度不是原⼦的.但是在硬件层⾯上可以让⼀条指令完成这个 操作,也就变成原⼦的了.

synchronized

锁升级

JVM将synchronized锁分为⽆锁、偏向锁、轻量级锁、重量级锁状态。会根据情况,进⾏依次升 级。

1)偏向锁

 第⼀个尝试加锁的线程,优先进⼊偏向锁状态. 

偏向锁不是真的"加锁",只是给对象头中做⼀个"偏向锁的标记",记录这个锁属于哪个线程.

 如果后续没有其他线程来竞争该锁,那么就不⽤进⾏其他同步操作了(避免了加锁解锁的开销)

如果后续有其他线程来竞争该锁(刚才已经在锁对象中记录了当前锁属于哪个线程了,很容易识别当前 申请锁的线程是不是之前记录的线程),那就取消原来的偏向锁状态,进⼊⼀般的轻量级锁状态.

偏向锁本质上相当于"延迟加锁".能不加锁就不加锁,尽量来避免不必要的加锁开销. 但是该做的标记还是得做的,否则⽆法区分何时需要真正加锁.

2)轻量级锁

随着其他线程进⼊竞争,偏向锁状态被消除,进⼊轻量级锁状态(⾃适应的⾃旋锁). 此处的轻量级锁就是通过CAS来实现.

 • 通过CAS检查并更新⼀块内存(⽐如null=>该线程引⽤)

 • 如果更新成功,则认为加锁成功

 • 如果更新失败,则认为锁被占⽤,继续⾃旋式的等待(并不放弃CPU).

 ⾃旋操作是⼀直让CPU空转,⽐较浪费CPU资源. 因此此处的⾃旋不会⼀直持续进⾏,⽽是达到⼀定的时间/重试次数,就不再⾃旋了. 也就是所谓的"⾃适应"

3)重量级锁

 如果竞争进⼀步激烈,⾃旋不能快速获取到锁状态,就会膨胀为重量级锁 此处的重量级锁就是指⽤到内核提供的mutex.

 • 执⾏加锁操作,先进⼊内核态.

 • 在内核态判定当前锁是否已经被占⽤

 • 如果该锁没有占⽤,则加锁成功,并切换回⽤⼾态.

 • 如果该锁被占⽤,则加锁失败.此时线程进⼊锁的等待队列,挂起.等待被操作系统唤醒.

 • 经历了⼀系列的沧海桑⽥,这个锁被其他线程释放了,操作系统也想起了这个挂起的线程,于是唤醒 这个线程,尝试重新获取锁.

锁消除

编译器+JVM判断锁是否可消除.如果可以,就直接消除.

什么是"锁消除" 

有些应⽤程序的代码中,⽤到了synchronized,但其实没有在多线程环境下.(例如StringBuffer)

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

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

锁粗化

⼀段逻辑中如果出现多次加锁解锁,编译器+JVM会⾃动进⾏锁的粗化.

 锁的粒度:粗和细

实际开发过程中,使⽤细粒度锁,是期望释放锁的时候其他线程能使⽤锁.

但是实际上可能并没有其他线程来抢占这个锁.这种情况JVM就会⾃动把锁粗化,避免频繁申请释放锁.

举个栗⼦理解锁粗化

滑稽⽼哥当了领导,给下属交代⼯作任务:

 ⽅式⼀:

 • 打电话,交代任务1,挂电话.

• 打电话,交代任务2,挂电话.

• 打电话,交代任务3,挂电话. 

⽅式⼆:

 • 打电话,交代任务1,任务2,任务3,挂电话.

 显然,⽅式⼆是更⾼效的⽅案.可以看到,synchronized的策略是⽐价复杂的,在背后做了很多事情,⽬的为了让程序猿哪怕啥都不懂,也不⾄于写出特别慢的程序.JVM开发者为了Java程序猿操碎了心.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/49769.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu22.04单个网口两个IP

其中 4网段IP可用来上网,3 网段用来内网 界面显示: 配置文件: 01-network-manager-all.yaml 放在 /etc/netplan/ # Let NetworkManager manage all devices on this systemnetwork:version: 2renderer: networkdethernets:eth0:dhcp4: falsedhcp6: …

开放式耳机哪个牌子好?五大超值机型整理,速速收藏!!

大家都知道现在的开放式耳机是越来越火了,后台也有非常多的小伙伴来私信,作为一个耳机测评师,当然是为了你们服务啦,所以这一期文章,就是为了个大家答疑解惑,告诉大家如何才能选购出一款比较好用的开放式耳…

万字长文详解Java反射技术 | JavaSE | Java进阶知识 | 源码

🙋大家好!我是毛毛张! 🌈个人首页: 神马都会亿点点的毛毛张 📌今天分享的是JavaSE中的进阶知识🛑:反射技术。内容有点长,非常全面,记得点赞👍、收藏✅加关…

【网络世界】HTTP协议

目录 🌈前言🌈 📁 概念 📁 URL 📂 urlencode 和 urldecode 📁 协议格式 📁 方法 📂 GET/get 📂 POST/post 📁 常见的报头 📁 状态码 &…

模型大小的指标和模型量化的指标和手段

一、模型大小的指标 1.计算量 计算次数,反映了模型对硬件计算单元的需求。计算量的单位是 OPs(Operations) 。最常用的数据格式 为 float32,因此float32类型下的计算量单位被写作 FLOPs (Floating Point Operations),即浮点计算次数。模型的…

3D Web轻量化引擎HOOPS Communicator针对复杂大模型Web端可视化的解决方案

随着工程设计、制造和建筑领域中三维模型的日益复杂化,如何在Web端高效处理和展示这些大规模数据成为一大挑战。HOOPS Communicator作为一款强大的3D可视化工具,提供了一套针对复杂大模型的轻量化解决方案,涵盖了模型轻量化及格式转换、超大模…

PostgreSQL成为最受欢迎的数据库; TiDB马拉松大赛开启, Serverless和Vector为比赛焦点

重要更新 1. TiDB Hackathon大赛报名开启,总奖金达21万,主题是基于 TiDB Serverless 内置的向量搜索功能(Vector Search)构建 AI 创新应用,感兴趣的可以报名参加。( [1] ) 2. Stack Overflow 2024 开发者调研结果公布…

自学JavaScript(放假在家自学第一天)

目录 JavaScript介绍分为以下几点 1.1 JavaScript 是什么 1.2JavaScript书写位置 1.3 Javascript注释 1.4 Javascript结束符 1.5 Javascript输入输出语法 JavaScript(是什么?) 是一种运行在客户端(浏览器)的编程语言,实现人机交互效果。 2.作用(做什么?)网…

从头开始微调Llama 3.1模型

在今天的科技专栏中,我们将深入探讨如何微调Llama 3.1模型,以使其更好地适应您的特定领域数据。微调大型语言模型(如Llama)的主要目的是为了在特定领域的数据上表现更好,从而生成更符合您需求的输出。以下是我们将要介…

SpringBoot知识笔记

一、基本概念 1.1 特性 起步依赖 自动配置 其它特性:内嵌的Tomcat、Jetty(无需部署WAR文件),外部配置,不需要XML配置(properties/yml)。 1.2 配置文件 SpringBoot提供了多种属性配置方式 //application.properties server.port=9090 server.servlet.context-path…

Python爬虫知识体系-----Urllib库的使用

数据科学、数据分析、人工智能必备知识汇总-----Python爬虫-----持续更新:https://blog.csdn.net/grd_java/article/details/140574349 文章目录 1. 基本使用2. 请求对象的定制3. 编解码1. get请求方式:urllib.parse.quote()2. ur…

邦布带你从零开始实现图书管理系统(java版)

今天我们来从零开始实现图书管理系统。 图书管理系统 来看我们的具体的实现,上述视频。 我们首先来实现框架,我们要实现图书管理系统,首先要搭框架。 我们首先定义一个书包,在书包中定义一个书类和一个书架类,再定义…

用Java手写jvm之实现查找class

写在前面 完成类加载器加载class的三阶段,加载,解析,初始化中的加载😀😀😀 源码 。 jvm想要运行class,是根据类全限定名称来从特定的位置基于类加载器来查找的,分别如下:…

【SQL 新手教程 2/20】关系模型 -- 主键

💗 关系数据库建立在关系模型上⭐ 关系模型本质上就是若干个存储数据的二维表 记录 (Record): 表的每一行称为记录(Record),记录是一个逻辑意义上的数据 字段 (Column):表的每一列称为字段(Colu…

吴恩达的TranslationAgent学习

TranslationAgent构成 整个[TranslationAgent (github.com)]在流程上分为短文本的一次性翻译和长文本的分chunk翻译(按照Token进行划分)。 但是不论长文本翻译还是短文本翻译,总体流程遵循执行、纠正再执行的逻辑循环实现。 这种按照自省思路…

【数字IC/FPGA】使用Verdi对比两个波形

步骤一: 使用verdi打开第一个波形 bsub verdi -ssf 1.fsdb添加需要观察的信号,如下图所示: 步骤二: 新建容器,依次点击Window --> Dock to --> New Container Window。 然后输入容器的名字,如下图所…

SQL数据库:通过在视频监控平台服务器上直接使用SQL存储过程,在海量记录中查询特定时间段内-某个摄像头的所有视频片段

目录 一、背景 1、存储过程 2、视频监控系统 二、需求和数据表 1、具体要求 2、数据表 3、部分数据 三、实现 1、目标 2、创建存储过程 (1)存储过程代码 (2)创建成功 3、存储过程的解释 4、SQL命令调用方式 5、调用…

Java----队列(Queue)

目录 1.队列(Queue) 1.1概念 1.2队列的使用 1.3队列的模拟实现 1.4循环队列 1.4.1循环队列下标偏移 1.4.2如何区分队列是空还是满 1.5双端队列 (Deque) 1.队列(Queue) 1.1概念 队列:只允许在一端进行插入数据…

Linux Redhat ens33不显示IP问题

优质博文:IT-BLOG-CN 【第一步】:查看系统网卡设备 : ip addr show 【第二步】:修改网卡配置参数 cd /etc/sysconfig/network-scripts/ vi ifcfg-ens33 修改ONBOOT参数为yes 【第三步】:重启网卡,然后ping检测…

奇怪的Excel单元格字体颜色格式

使用VBA代码修改单元格全部字符字体颜色是个很简单的任务,例如设置A1单元格字体颜色为红色。 Range("A1").Font.Color RGB(255, 0, 0)有时需要修改部分字符的颜色,如下图所示,将红色字符字体颜色修改为蓝色。代码将会稍许复杂&am…