多线程 - 锁策略 CAS
常见的锁策略
此处谈到的锁策略,不局限于 Java,C++,Python,数据库,操作系统……但凡是涉及到锁,都是可以应用到下列的锁策略的
乐观锁 vs 悲观锁
锁的实现者,预测接下来锁冲突(锁竞争,两个线程针对一个对象加锁,产生阻塞等待了)的概率是大,还是不大,根据这个冲突的概率,来接下来做什么
~~ 这不是两把具体的锁,而是“两类锁”.
悲观锁:预测锁竞争不是很激烈.
乐观锁:预测锁竞争会很激烈.
通常来说,悲观锁一般做的工作更多一些,效率更低一些,乐观锁做的工作会更少一些,效率更高一点.但是并不绝对.
悲观锁和乐观锁,唯一的区别,主要就是看预测锁竞争激烈程度的结论.
轻量级锁 vs 重量级锁
轻量级锁: 加锁解锁,过程更快更高效.
重量级锁: 加锁解锁,过程更慢,更低效.
一个乐观锁很可能也是一个轻量级锁,一个悲观锁很可能也是一个重量级锁.
多数情况下,乐观锁,也是一个轻量级锁.
多数情况下,悲观锁也是一个重量级锁.
自旋锁 vs 挂起等待锁
自旋锁是轻量级锁的一种典型实现.
挂起等待锁是重量级锁的一种典型实现.
互斥锁 vs 读写锁
互斥锁
synchronized,是互斥锁
synchronized 只有两个操作:
1.进入代码块,加锁
2.出了代码块,解锁
加锁,就只是单纯的加锁,没有更细化的区分了
读写锁
~~ 读写锁,能够把读和写两种加锁区分开
读写锁:
1.给读加锁
2.给写加锁
3.解锁
注: 如果多个线程读同一个变量,不会涉及到线程安全问题!!!
读写锁中,约定:
1.读锁和读锁之间,不会锁竞争.不会产生阻塞等待,不会影响程序的速度,代码执行很快.
2.写锁和写锁之间,有锁竞争,减慢速度,但是保证准确性.
3.读锁和写锁之间,也有锁竞争,减慢速度,但是保证准确性.
注:
1.非必要不加锁.
2.读写锁更适合于,一写多读的情况.
3.多线程针对同一个变量并发读,这时是没有线程安全问题的,也就不需要加锁控制.
4.很多开发场景中,读操作非常高频,比写操作的频率高很多.
5.在Java标准库里面也提供了读写锁的具体实现(两个类,读锁类,写锁类).
公平锁 vs 非公平锁
此处把公平定义成“先来后到”
公平锁: 当女神分手之后,就由等待队列中,最早来的舔狗上位.
非公平锁: 雨露均沾了.
注: 操作系统和 Java synchronized 原生都是“非公平锁”,操作系统这里的针对加锁的控制,本身就依赖于线程调度顺序.这个调度顺序是随机的,不会考虑到这个线程等待锁多久了.
要想实现公平锁,就得在这个基础上,能够引入额外的东西(引入一个队列,让这些加锁的线程去排队).
可重入锁 vs 不可重入锁
不可重入锁: 一个线程针对一把锁,连续加锁两次,出现死锁.
可重入锁: 一个线程针对一把锁,连续加锁多次都不会死锁.
注: 系统原生的锁,C++标准库的锁,Python标准库的锁…都不是可重入的锁!
synchronized是个"可重入锁",(加锁的时候会判定一下,看当前尝试申请锁的线程是不是已经就是锁的拥有者了,如果是,直接放行)
synchronized锁
针对上述六组锁策略, synchronized这把锁属于哪种呢??
synchronized 既是悲观锁,也是乐观锁 ~~ synchronized会根据当前锁竞争的激烈程度,自适应.
既是轻量级锁,也是重量级锁 ~~ synchronized默认是轻量级锁,如果发现当前锁竞争比较激烈,就会转换成重量级锁.
synchronized这里的轻量级锁部分基于自旋锁的方式实现,synchronized这里的重量级锁部分基于挂起等待锁的方式实现.
synchronized不是读写锁.
synchronized是非公平锁.
synchronized是可重入锁.
总结: 上述谈到的六种锁策略,可以视为是“锁的形容词”.
CAS
CAS ~~ 全称Compare and swap, 字面意思:”比较并交换“
一个 CAS 涉及到以下操作 :
我们假设内存中的原数据V,旧的预期值A,需要修改的新值B。
1.比较 A 与 V 是否相等。(比较)
2.如果比较相等,将 B 写入 V。(交换)
3.返回操作是否成功
此处最特别的地方,上述这个 CAS 的过程,并非是通过一段代码实现的,而是通过一条 CPU 指令完成的 => CAS 操作是原子的 ~~ 就可以在一定程度上回避线程安全问题
因此解决线程安全问题除了加锁之外,又有了一个新的方向了.
小结: CAS 可以理解成是 CPU 给我们提供的一个特殊指令,通过这个指令,就可以一定程度的处理线程安全问题.
CAS 伪代码
注: 下面写的代码不是原子的, 真实的 CAS 是一个原子的硬件指令完成的. 这个伪代码只是辅助理解 CAS 的工作流程.
CAS 的应用场景
1.实现原子类(Java 标准库里提供的类)
标准库中提供了
java.util.concurrent.atomic
包, 里面的类都是基于这种方式来实现的.典型的就是AtomicInteger
类,其中的getAndIncrement
相当于i++
操作.
import java.util.concurrent.atomic.AtomicInteger;/*** Created with IntelliJ IDEA.* Description:* User: fly(逐梦者)* Date: 2023-10-09* Time: 10:49*/
public class ThreadDemo28 {public static void main(String[] args) throws InterruptedException {// 这些原子类,就是基于 CAS 实现了 自增,自减等操作.此时进行这类操作不需要加锁,也是线程安全的.AtomicInteger count = new AtomicInteger(0);// 使用原子类, 来解决线程安全问题Thread t1 = new Thread(() -> {for (int i = 0; i < 5_0000; i++) {// 因为 java 不支持运算符重载,所以只能使用普通方法来表示自增自减count.getAndIncrement();// count++//count.incrementAndGet(); => ++ count//count.getAndDecrement(); => count--//count.decrementAndGet(); => -- count}});Thread t2 = new Thread(() -> {for (int i = 0; i < 5_0000; i++) {count.getAndIncrement();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count.get());}
}
伪代码实现AtomicInteger
2.实现自旋锁
自旋锁伪代码
注: CAS 属于“特殊方法”,synchronized 属于“通用方法” –> 各种场景,都能使用(打击面广)
CAS 的典型问题: ABA 问题
CAS 在运行中的核心,检查 value 和 oldValue 是否一致.如果一致,就视为value 中途没有被修改过,所以进行下一步交换操作是没问题的.
这里一致,可能是没改过.也可能是,改过,但是还原回来了?!
把 value 的值设为A的话, CAS 判定 value 为 A,此时可能确实value始终是A,也可能是value本来是A,被改成了B,又还原成了A …
ABA 问题就相当于,买个手机,买到的这个手机,可能是新机,也可能是翻新机.
翻新机: 二手的,被销售商回收了,经过一些翻新操作(把外壳换了,重新包装).
ABA 这个情况,大部分情况下,其实是不会对代码/逻辑产生太大影响的,但是不排除一些“极端情况”,也是可能造成影响的.
例子:
上述场景,概率非常低!!!一方面,恰好,滑稽这边多按了几次,产生多个扣款动作了,另一方面,恰好在这个非常极限的时间内,有人转账了一样的金额.
解决方案
针对当前问题,采取的方案,就是加入一个版本号.想象成,初始版本号是1,每次修改版本号都+1,然后进行 CAS 的时候不是以金额为基准了,而是以版本号为基准.此时,版本号要是没变,就是一定没有发生改变(版本号是只能增长,不能降低的).
相关文章:

多线程 - 锁策略 CAS
常见的锁策略 此处谈到的锁策略,不局限于 Java,C,Python,数据库,操作系统……但凡是涉及到锁,都是可以应用到下列的锁策略的 乐观锁 vs 悲观锁 锁的实现者,预测接下来锁冲突(锁竞争,两个线程针对一个对象加锁,产生阻塞等待了)的概率是大,还是不大,根据这个冲突的概率,来接下…...

VP记录——The 2021 CCPC Weihai Onsite
网址 2021CCPC威海 赛时过题与罚时 A.Goodbye, Ziyin! 签到题,队友写的 #include<bits/stdc.h> using namespace std; int cnt[10], de[1000010]; int main() {int n;cin >> n;for(int i 1; i < n; i) {int u, v;scanf("%d %d", &…...

JavaWeb---Servlet
1.Srvlet概述 Servlet是运行在java服务器端的程序,用于接收和响应来着客户端基于HTTP协议的请求 如果想实现Servlet的功能,可以通过实现javax。servlet。Servlet接口或者继承它的实现类 核心方法:service()…...

英语——方法篇——单词——谐音法+拼音法——50个单词记忆
theatre,剧场,太后th吃eat热re食物,就去剧场了 loud dolphin,做do脸皮厚plh在。。。里 humid,hu湖mi米d的 blender,b爸lend借给er儿。 tragedy,tr土人...

35道Rust面试题
这套Rust面试题包括了填空题、判断题、连线题和编码题等题型。 选择题 1 ,下面哪个是打印变量language的正确方法? A,println("{}", language); B,println(language); C,println!("{}", langu…...

01 时钟配置初始化,debug
1. 开启debug series,否则只能下载一次,再次下载要配置boot 2.f0外部时钟配置 h750 配置 实测可用...

Halcon我的基础教程(一)(我的菜鸟教程笔记)-halcon仿射变换(Affine Transformation)的探究与学习
目录 什么是仿射变换?仿射变换有哪些方式?任何仿射变换都能由以下基本变换构造而来:在Halocn中,仿射变换具有重要的作用,那我们本文章重点讨论仿射变换基础性知识。 使用Halcon中的重要算子,仿射变换一般解决步骤,案例应用会在以后的文章中我们重点解答与讨论。 我们首先…...

c++视觉---中值滤波处理
中值滤波(Median Filter)是一种常用的非线性平滑滤波方法,用于去除图像中的噪声。它不像线性滤波(如均值滤波或高斯滤波)那样使用权重来计算平均值或加权平均值,而是选择滤波窗口内的像素值中的中间值作为输…...

Edge使用猴油脚本实战(实验室安全考试系统刷在线时长——网站永久自动刷新)
介绍 篡改猴 (Tampermonkey) 是拥有 超过 1000 万用户 的最流行的浏览器扩展之一。它允许用户自定义并增强您最喜爱的网页的功能。用户脚本是小型 JavaScript 程序,可用于向网页添加新功能或修改现有功能。使用 篡改猴,您可以轻松在任何网站上创建、管理…...

Vue 中 KeepAlive 内置缓存使用
KeepAlive 介绍及使用场景 KeepAlive 是 vue 中的内置组件,当多个组件动态切换时可以对实例状态进行缓存,用法如下 <router-view v-slot"{ Component }"><keep-alive><component :is"Component" /></keep-al…...

语言模型编码中/英文句子格式详解
文章目录 前言一、Bert的vocab.txt内容查看二、BERT模型转换方法(vocab.txt)三、vocab内容与模型转换对比四、中文编码总结 前言 最近一直在学习多模态大模型相关内容,特别是图像CV与语言LLM模型融合方法,如llama-1.5、blip、meta-transformer、glm等大…...

【Node.js】路由
基础使用 写法一: // server.js const http require(http); const fs require(fs); const route require(./route) http.createServer(function (req, res) {const myURL new URL(req.url, http://127.0.0.1)route(res, myURL.pathname)res.end() }).listen…...
matlab 2ask 4ask 信号调制
1 matlab 2ask close all clear all clcL =1000;Rb=2822400;%码元速率 Fs =Rb*8; Fc=Rb*30;%载波频率 Ld =L*Fs/Rb;%产生载波信号 t =0:1/Fs:L/Rb;carrier&...

Python利用jieba分词提取字符串中的省市区(字符串无规则)
目录 背景库(jieba)代码拓展结尾 背景 今天的需求就是在一串字符串中提取包含,省、市、区,该字符串不是一个正常的地址;,如下字符串 "安徽省、浙江省、江苏省、上海市,冷运标快首重1kg价格xx元,1.01kg(含)-5kg(不含)续重价…...
MuLogin防关联浏览器帮您一键实现Facebook账号多开
导言: 在当今数字化时代,社交媒体应用程序的普及程度越来越高。Facebook作为全球最大的社交媒体平台之一,拥有数十亿的用户。然而,对于一些用户来说,只拥有一个Facebook账号可能无法满足他们的需求。有时,…...

【C语言】每日一题(半月斩)——day4
目录 选择题 1、设变量已正确定义,以下不能统计出一行中输入字符个数(不包含回车符)的程序段是( ) 2、运行以下程序后,如果从键盘上输入 65 14<回车> ,则输出结果为( &…...
Are you sure you want to continue connecting (yes/no) 每次ssh进
Lunix scp等命令不需要输入yes确认方法_scp不需要确认-CSDN博客 方法一:连接时加入StrictHostKeyCheckingno ssh -o StrictHostKeyCheckingno root192.168.1.100 方法二:修改/etc/ssh/ssh_config配置文件,添加: StrictHostKeyC…...
网络与信息系统安全设计规范
1、总则 1.1、目的 为规范XXXXX单位信息系统安全设计过程,确保整个信息安全管理体系在信息安全设计阶段符合国家相关标准和要求,特制订本规范。 1.2、范围 本规范适用于XXXXX单位在信息安全设计阶段的要求和规范管理。 1.3、职责 网络安全与信息化…...

在Linux怎么用vim实现把一个文件里面的文本复制到另一个文件里面
2023年10月9日,周一下午 我昨天遇到了这个问题,但在网上没找到图文并茂的博客,于是我自己摸索出解决办法后,决定写一篇图文并茂的博客。 情景 假设现在我要用vim把file_transfer.cpp的内容复制到file_transfer.hpp里面 第一步 …...
CCAK—云审计知识证书学习
目录 一、CCAK云审计知识证书概述 二、云治理概述 三、云信任 四、构建云合规计划 <...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...