CAS概述
目录
- 一、CAS与原子类
- 1.1 CAS
- 1.2 乐观锁与悲观锁
- 1.3 原子操作类
- 二、 synchronized优化
- 2.1 轻量级锁
- 2.2 轻量级锁-无竞争
- 2.3 轻量级锁-锁膨胀
- 2.4 重量级锁-自旋
- 2.5 偏向锁
- 2.6 synchronized-其他优化
一、CAS与原子类
1.1 CAS
CAS(一种不断尝试)即Compare and Swap,它体现的一种乐观锁的思想,比如多个线程要对一个共享的整形变量执行+1操作:
CompareAndSwap:尝试把结果赋值给前面的共享变量,赋值的同时将旧值与共享变量当前的值作比较【怕写入结果时有其他线程已经将共享变量的值修改】
获取共享变量时,为了保证该变量的可见性,需要使用volatile修饰。结合CAS和volatile可以实现无锁并发,使用于竞争不激烈、多核CPU的场景下。
● 因为没有使用synchronized,所以线程不会陷入阻塞(CAS需要不断重试进而利用CPU时间),这是效率提升的因素之一
● 但如果因为竞争激烈,可以想到重连必然频繁发生,反而效率会受影响
CAS底层依赖于一个Unsafe类来直接调用操作系统底层的CAS指令,下面是直接使用Unsafe对象进行线程安全保护的例子
1.2 乐观锁与悲观锁
● CAS是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算修改了也没关系,花费点时间再重试而已
● synchronized是基于悲观锁的思想:最悲观的估计,时刻得防着其他线程来修改共享变量,只要线程上了锁就别想修改,完全解开了锁其他线程才有机会
1.3 原子操作类
juc(java.util.concurrent)Java并发工具包中提供了原子操作类,可以提供线程安全的操作,例如:AtomicInteger(原子整数类===>保护整数操作自增、自减的一些线程安全操作)、AtomicBoolean等,它们底层就是采用CAS技术+volatile来实现的。
import java.util.concurrent.atomic.AtomicInteger;
public class Test {// 创建原子整数对象(给一个初始值0)private static AtomicInteger i=new AtomicInteger(0);public static void main(String[] args) throws InterruptedException {Thread t1=new Thread(()->{for (int j = 0; j < 5000 ; j++) {i.getAndIncrement(); // 获取并且自增 i++// i.incrementAndGet(); // 自增并且获取 ++i}});Thread t2 = new Thread(()-> {for (int j = 0; j < 5000; j++) {i.getAndDecrement(); // 获取并且自减 i--}});t1.start();t2.start();// 让主线程等待,一直等待其他线程不再活动为止 //t1.join();t2.join();System.out.println(i);}
}
结果并不会出现整数、负数的情况(利用无锁并发的方式来保证原子整数类中整数信息的线程安全)
二、 synchronized优化
Java HotSPot虚拟机中,每个对象都有对象头(包括class指针和Mark Word)。Mark Word平时储存这个对象的哈希值、分代年龄,当加锁时,这些信息就根据情况被替换为标记位、线程锁记录指针、重量级锁指针、线程ID等内容
2.1 轻量级锁
如果一个对象虽然有多线程访问,但多线程访问的时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化。这就好比:
学生(线程A)用课本占座(轻量级锁好比用课本占座,座位好比CPU的使用权),上了半节课,出门了(CPU时间到),回来一看, 发现课本没变,说明没有竞争,继续上他的课。
如果这期间有其它学生(线程B) 来了,会告知(线程A)有并发访问,线程A随即升级为重量级锁,进入重量级锁的流程。【锁膨胀:轻量级锁升级为重量级锁】
而重量级锁就不是用课本占座那么简单了,可以想象线程A走之前,把座位用一个铁栅栏围起来
假设有两个方法同步块,利用同一个对象加锁
static Object obj=new Object();public static void method1(){synchronized (obj){// 同步块 Amethod2();}}private static void method2() {synchronized (obj){// 同步块B }}
2.2 轻量级锁-无竞争
每个线程的栈帧中都会包含一个锁记录的结构,内部可以存储锁定对象的Mark Word(8个字节)
栈帧中锁记录的结构的作用:对一个对象加锁后,需将原来旧的信息暂存到栈帧的锁记录结构中,将来解锁时,再将暂存的Mark Word旧的信息恢复回去
对以上代码的加锁、解锁流程:
2.3 轻量级锁-锁膨胀
如果在尝试加轻量级锁的过程中,CAS操作无法成功,这是一种情况就是有其他线程为此对象加上了轻量级锁(有竞争),这时需要进行锁膨胀,将轻量级锁升级为重量级锁。
static Object obj = new Object();public static void method1 () {synchronized (obj) {// 同步块}}
2.4 重量级锁-自旋
重量级锁竞争的时候,还可以使用自选来进行优化,如果当前线程自旋成功(即这个时候持锁线程已经退出了同步块,释放了锁),这时当前线程就可以避免阻塞。
在Java 6之后自旋锁是自适应的,比如对象刚刚的一次自旋操作成功过,那么认为这次自旋成功的可能性会高,就多自旋几次;反之,就少自旋甚至不自旋,总之,比较智能。
● 自旋会占用CPU时间,单核CPU自旋就是浪费(单核CPU无闲置CPU)毫无意义,多核CPU自旋才会发挥优势
● 好比等红灯时汽车是不是熄火,不熄火相当于自旋(等待时间短了划算),熄火相当于阻塞(等待时间长了不划算)
● Java 7之后不能再控制是否开启自旋功能
①: 自旋重试成功的情况【当线程2也想加锁(获取monitor)时,发现不能加锁时并不会马上陷入阻塞】
②: 自旋重试失败的情况【线程2不可能无限制的自旋重试,若线程1执行的时间较长,在重试过程中同步代码块还未执行完,重试多次后会放弃重试,然后自己陷入阻塞】
2.5 偏向锁
假设有两个方法同步块,利用同一个对象加锁
锁重入:线程1对对象加锁,由于其调用方法2,方法2还是本线程对同一对象加锁,但每次进行锁重入时还是会用CAS再做一次修改Mark Word为线程1的锁记录地址这样的操作
如何优化以上存在的问题?===>JDK 6中引入偏向锁的概念做进一步优化
轻量级锁在没有竞争时(就自己这个线程) , 每次重入仍然需要执行CAS操作。Java 6中引入了偏向锁来做进一步优化:只有第一次使用CAS将线程ID设置到对象的Mark Word头,之后发现这个线程ID是自己的就表示没有竞争,不用重新CAS.
■ 撤销偏向需要将持锁线程升级为轻量级锁,这个过程中所有线程需要暂停(STW)
■ 访问对象的hashCode也会撤销偏向锁(无锁状态下,对象头中存储的为对象的hashCode;加上偏向锁后,对象头中存的为线程ID,hashCode被放到加锁线程中)
■ 如果对象虽然被多个线程访问,但没有竞争,这时偏向了线程TI的对象仍有机会重新偏向T2, (FL)中J重置对象的Thread ID
■ 撤销偏向和重偏向都是批量进行的,以类为单位
■ 如果撤销偏向到达某个阈值,整个类的所有对象都会变为不可偏向的
■ 可以主动使用-XX:-UseBiasedL ocking禁用偏向锁
可以参考此篇论文: https://www.oracle .com technetwork/java biasedlocking -oopsla2006-wp- 149958.pdf
2.6 synchronized-其他优化
① 减少上锁时间 :同步代码块中尽量短
② 减少锁的粒度 :将一个锁拆分为多个锁提高并发度
例如:
■ ConcurrentHashMap
■ LongAdder(进行计数的原子操作类)分为base和cells 两部分。没有并发争用的时候或者是cells数组正在初始化的时候,会使用CAS来累加值到base,有并发争用,会初始化cells数组,数组有多少个cell,就允许有多少线程并行修改,最后将数组中每个cell累加,再加上base就是最终的值
■ LinkedBlockingQueue 入队和出队使用不同的锁,相对于I inkedBlockingArray只有一个锁效率要高
③ 锁粗化 :
多次循环进入同步块不如同步块内多次循环
另外JVM可能会做如下优化,把多次append的加锁操作粗化为一次(因为都是对同一个对象加锁,没必要重入多次)
// StringBuffer类是线程安全的【里面的append()方法会有synchronized来进行同步保护】 new StringBuffer().append("a").append("b").append("c");
④ 锁消除 :当对象没有机会被外界用到时,就会将对象上的锁消除掉
JVM会进行代码的逃逸分析,例如某个加锁对象是方法内局部变量,不会被其他线程访问到,这时候就会被即时编译器忽略掉所有同步操作。
⑤ 读写分离 :
CopyOnWriteArrayList:(读)读取原始数组的内容;
CopyOnWriteSet:(写)复制一份,在一个新数组上进行;
因此读操作不同同步,只需要对写操作进行同步即可
参考:
https://wiki.openjdk. java.net/display/HotSpot/Synchronization
http://luojinping.com/2015/07/09/javai)iít1c/
https://www.infoq.cn/article/java-se- 16-synchronized
https://www.jianshu.com/p/9932047a89be
https://www.cnblogs.com/sheeva/p/6366782.html
https://stackoverflow.com/questions/463 12817/does-java-ever-rebias-an-individual-lock
相关文章:

CAS概述
目录一、CAS与原子类1.1 CAS1.2 乐观锁与悲观锁1.3 原子操作类二、 synchronized优化2.1 轻量级锁2.2 轻量级锁-无竞争2.3 轻量级锁-锁膨胀2.4 重量级锁-自旋2.5 偏向锁2.6 synchronized-其他优化一、CAS与原子类 1.1 CAS CAS(一种不断尝试)即Compare …...

Ansys Zemax / SPEOS | 光源文件转换器
本文解释了如何在 SPEOS 与 Zemax 之间转换二进制光源文件。 下载 联系工作人员获取附件 简介 在本文中,为用户提供了一组Python代码,用于在Zemax和SPEOS之间转换源文件。 有些光源,如 .IES 文件,可在 SPEOS 和 Zemax 中进行…...
PRML笔记2-关于回归参数w的先验的理解
接上篇,现在考虑给w\boldsymbol{w}w加入先验,考虑最简单的假设,也就是w\boldsymbol{w}w服从均值为0,协方差矩阵为α−1I\alpha^{-1}\boldsymbol{I}α−1I的高斯分布。 p(w∣α)N(w∣0,α−1I)(α2π)(M1)/2exp{−α2wTw}\begin{…...
Selenium原理
我们使用Selenium实现自动化测试,主要需要3个东西1.测试脚本,可以是python,java编写的脚本程序(也可以叫做client端)2.浏览器驱动, 这个驱动是根据不同的浏览器开发的,不同的浏览器使用不同的webdriver驱动…...
Disconf、Apollo和Nacos分布式配置框架差异对比
差异对比表格: 功能点DisconfApolloNacos依赖高可用框架完全依赖于Zookeeper来实现监听拉取,向外提供了HTTP拉取数据接口依赖于Eureka实现内部服务发现注册,提供HTTP接口给Client SDK拉取监听数据内部自研实现框架高可用CAP理论偏重点Zookee…...
高新技术企业认定条件条件 高企认定要求
高新技术企业认定条件 一、成立年限:申报企业须注册成立365个日历天数,而非一个会计年度。 二、知识产权 (1)申报企业必须拥有在中国境内授权或审批审定的知识产权,且知识产权在有效保护期内。知识产权权属人应为申请企…...
华为OD机试 - 新学校选址(JavaScript) | 机试题+算法思路+考点+代码解析 【2023】
新学校选址 题目 为了解新学期学生暴涨的问题,小乐村要建立所新学校 考虑到学生上学安全问题,需要所有学生家到学校的距离最短. 假设学校和所有学生家都走在一条直线之上,请问学校建立在什么位置, 能使得到学校到各个学生家的距离和最短 输入 第一行: 整数 n 取值范围 [1,1…...

二进制部署K8S
目录 一、环境准备 1、常见的k8s部署方式 2、关闭防火墙 3、关闭selinux 4、关闭swap 5、根据规划设置主机名 6、在master添加hosts 7、将桥接的IPv4流量传递到iptables的链 8、时间同步 二、部署etcd集群 1、master节点部署 2、查看证书的信息 2.1 创建k8s工作目…...
高效获知Activity的生命周期
Activity生命周期监听 使用 Instrumentation 对 Activity 生命周期进行监听。 优点: 全局仅一次反射,性能影响极小所有Activity的生命周期都能够被监听到由于Java的单继承,为了拓展性,可以使用装饰器模式对Instrumentation进行功…...

分析现货黄金价格一般有什么方法
分析现货黄金价格一般有什么方法呢?我相信很多投资者都会说,是技术分析。很多人并不知道技术分析是什么,并且技术分析是如何去分析现货黄金价格的,那么本文就介绍一下技术分析的主要分类。可以说,小编的其他文章都是以…...

Spring中的拦截器
这里写目录标题基本概念HandlerInterceptor拦截器HandlerInterceptor讲解MethodInterceptor拦截器二者的区别基本概念 在web开发中,拦截器是经常用到的功能。它可以帮我们预先设置数据以及统计方法的执行效率等等。 Spring中拦截器主要分两种,一个是Han…...
【Linux操作系统】【综合实验四 Linux的编译环境及线程编程】
文章目录一、实验目的二、实验要求三、实验内容四、实验报告要求一、实验目的 要求熟悉Linux环境中的程序编译、调试与项目管理过程并能实现具体操作;熟练使用基础函数库中与线程库中的管理函数,实现用户线程编程过程,并深入了解Linux的线程…...
Switch 如何使用NSCB 转换XCI NSP NSZ教程
很多小白经常碰到Switch游戏文件格式和预期不符的情况,比如碰到nsz自己不会安装(安装NSZ格式文件教程);或者是碰到xci格式的,想转换为nsp;抑或想将nsz格式文件还原回nsp格式。本文对此提供了解决方案。 文中…...

JVM12 字节码指令集
1. 概述 2. 加载与存储指令 2.1. 局部变量压栈指令 iload 从局部变量中装载int类型值 lload 从局部变量中装载long类型值 fload 从局部变量中装载float类型值 dload 从局部变量中装载double类型值 aload 从局部变量中装载引用类型值(refernce) iload_0 从…...
centos之python安装与多版本python之间的共存
一、背景 随着python版本迭代加快,有写python模块再低版本无法运行,此时需要我们在进行安装一个python版本 例如:uvloop 在python3.7上运行;python 3.6官方不再维护与更新 有些模块或不支持较低版本、有些模块支持较高版本python…...
SpringBoot学习笔记(一)
Idea中隐藏指定文件或指定类型文件 setting->File Types->Ignored Files and Folders输入要隐藏的文件名,支持*号通配符回车确认添加 SpringBoot概述 parent 小结: 开发SpringBoot程序要继承spring-boot-starter-parentspring-boot-starter-pa…...

美国原装KEYSIGHT E4981A(安捷伦) E4981A电容计
KEYSIGHT E4981A(安捷伦) Keysight E4981A(安捷伦)电容计为生产线中的陶瓷电容器测试提供了高速、可靠的测量。E4981A 实现了电容从小到大的测量能力,测量准确。Agilent E4981A 电容计有助于提高测试吞吐量࿰…...

K8S的基础概念
目录 一、k8s概述 1、k8s简介 1.1 k8s的作用 1.2 k8s的由来 1.3 k8s的含义 1.4 k8s的官网 1.5 GitHub 2、为什么要用 K8S? 2.1 K8s的目标 2.2 K8s解决了裸跑Docker 的若干痛点: 2.3 K8s的主要功能 3、K8s的特性 二、Kubernetes 集群架构与组件 1、工作流程 2、…...

【数据结构】——环形队列
文章目录一.环形队列的定义及其特点二.使用数组来实现环形队列1.创建一个队列2.初始化队列3. 判断环形队列是否为空4.判断环形队列是否已满5. 向循环队列插入元素,插入成功返回真6.删除环形链表的数据7. 取队头元素8.取队尾元素8.释放空间总结一.环形队列的定义及其…...

windows 安装Qt
下载 下载地址https://download.qt.io/,此文已5.7.0为例子。 根据图片依次选择即可。 安装 安装过程参考另一篇文章Ubuntu 安装 Qt5.7.0即可 配置环境变量 ps:我就是之前没配置环境变量,直接使用创建项目,项目源码直接运行是…...

Linux系统编程-DAY10(TCP操作)
一、网络模型 1、服务器/客户端模型 (1)C/S:client server (2)B/S:browser server (3)P2P:peer to peer 2、C/S与B/S区别 (1)客户端不同&#…...

CAD实体对象智能识别
CAD实体对象智能识别 概述 实体对象智能识别能够在CAD图纸中智能识别和匹配相似的实体对象。该系统采用模式匹配算法,支持几何变换(缩放、旋转),并提供了丰富的配置选项和可视化界面。 系统提供两种主要的识别方式:…...

基于51单片机的红外防盗及万年历仿真
目录 具体实现功能 设计介绍 资料内容 全部内容 资料获取 具体实现功能 具体功能: (1)实时显示年、月、日、时、分、秒、星期信息; (2)红外传感器(仿真中用按键模拟)检测是否有…...

vue项目使用svg图标
下面是在 Vue 3 项目中完整引入和使用 vite-plugin-svg-icons 的步骤 1、安装插件 npm install vite-plugin-svg-icons -D # 或 yarn add vite-plugin-svg-icons -D # 或 pnpm add vite-plugin-svg-icons -D 2、配置 Vite 在 vite.config.ts 或 vite.config.js 中配置&…...
大数据+智能零售:数字化变革下的“智慧新零售”密码
大数据+智能零售:数字化变革下的“智慧新零售”密码 大家好,今天咱们聊聊一个火到不行的话题:大数据在智能零售中的应用。这个领域,不仅是技术的“硬核战场”,更是商业创新的风口浪尖。谁能玩转数据,谁就能掌控消费者心智,实现销售爆发。 咱们不搞枯燥学术,而是用最“…...

LangChain工具集成实战:构建智能问答系统完整指南
导读:在人工智能快速发展的今天,如何构建一个既能理解自然语言又能调用外部工具的智能问答系统,成为许多开发者面临的核心挑战。本文将为您提供一套完整的解决方案,从LangChain内置工具包的基础架构到复杂系统的工程实践。 文章深…...
【学习记录】如何使用 Python 提取 PDF 文件中的内容
如何使用 Python 提取 PDF 文件中的内容 在文档自动化处理、数据提取和信息分析等任务中,从 PDF 文件中提取文本是一项常见需求。PDF 文件通常分为两种类型:基于文本的 PDF 和 包含扫描图像的 PDF。 本文将介绍如何使用 Python 分别提取这两种类型的 P…...

计算机组成与体系结构:补码数制二(Complementary Number Systems)
目录 4位二进制的减法 补码系统 🧠减基补码 名字解释: 减基补码有什么用? 计算方法 ❓为什么这样就能计算减基补码 💡 原理揭示:按位减法,模拟总减法! 那对于二进制呢?&…...
B站的视频怎么下载下来——Best Video下载器
B站(哔哩哔哩)作为国内最受欢迎的视频平台之一,聚集了无数优质内容:动漫番剧、游戏实况、学习课程、纪录片、Vlog、鬼畜剪辑……总有那么些视频让人想反复观看、离线观看,甚至剪辑创作。 但你是否遇到过这样的烦恼&am…...

从 Revit 到 3DTiles:GISBox RVT 切片器如何让建筑图元在 Web 端展示
在GIS(地理信息系统)行业蓬勃发展的当下,数据处理与展示的效率和精准度成为关键。GISBox作为一款功能强大的一站式三维GIS数据编辑、转换、发布平台,凭借其独特的“RVT切片器”功能,在RVT图元处理方面也有着不俗的表现…...