news 2026/5/11 19:05:32

简单学习 --> 线程安全(CAS原理)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
简单学习 --> 线程安全(CAS原理)

CAS

cas 是 Compare and swap (比较交换 , 比较交换的是内存 和 寄存器)

例如: 有一个内存 M, 和 两个寄存器 A , B

如果 M 和 A 的值相同 , 就把 B 赋值给 M ; 返回 true;

如果 M 和 A 的值不相同 , 就啥都不做 ; 返回 false

伪代码 , address 内存地址 ,

boolean CAS(address , expectvale , swapvalue){ if(&address == expctvale){ &address = swapvalue ; return true ; } return false ; }

CAS 的作用

CAS 本质是一个cpu 指令 那么这个操作 就是 原子的 , 可以使用 CAS 来完成一些操作 , 进一步代替 "加锁" ;

给编写线程安全的代码 ,就 引入了新的思路 ; 基于CAS 来实现线程安全的 方式 , 也称为 "无锁编程"

CAS cpu提供的指令 -> 被操作系统封装 , 提供api -> 被jvm封装 ,通过api -> 给我们使用 ;

优点:

保证线程安全, 同时避免阻塞(提供效率)

缺点:

1.代码更复杂 ;

2.只能够适合一些特殊场景, 没有加锁 更加广泛 ;

java中的CAS

基于CAS的原子类 Atomic

用 两个线程 count ++ ,每个线程++5000次, 因为并发编程,导致 最后结果不正确 ;

此时使用 原子类来 , 这样 count ++ ,操作就是原子的 ;

int count 我们 换成 AtomicInteger cont ;

代码

下面这些++操作或--操作 就都是原子的了 ;

//count ++ ; count.getAndIncrement(); // ++ count count.incrementAndGet() ; // count-- ; count.getAndDecrement(); // -- count count.decrementAndGet();

当我们点开这个++的方法,就可以看到 底层代码实现并没有加锁,而是使用了CAS

原子类伪代码实现

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

线程安全原理: 线程不安全就是因为 操作穿插执行 , CAS++ , 也是防止穿插执行 ;

加锁 ,通过阻塞 ,阻止穿插执行

CAS , 通过 反复的判断重试 , 避免穿插执行 ;

下面的while() 会在 value赋值成功后停止 , 如果value和 oldvalue不同就反复重试 ;

Atomic 里还有很多 原子类,

基于CAS 实现自旋锁

class SpinLock{ Thread owner = null ; // 锁的持有者 ; public void lock(){ // 自旋加锁 while(! CAS (owner , null , Thread.currentThread())){ // 如果owner 锁的持有者 不为空 就 ,自旋等待 // 如果 owner 为空 ,就是锁没有持有者,就立刻让调用加锁的线程马上加上锁 } } public void uLock(){ // 解锁 owner = null ; } ​ }

CAS 的 ABA问题

CAS: 是通过 value "没有发生改变" 作为 " 没有其他线程穿插执行" 过 的依据 ;

这种方式 , 不够严谨 , 像我们上面的 A -> B-> A ; 第一个线程a,拿到值 , 然后第二个线程B穿插执行 了 ,修改value的值 ,

对于第一个线程来说 , 好像这个值没变 , 但其实 A线程已经被B线程 穿插执行了 ;

value "没有发生改变" 作为 " 没有其他线程穿插执行" 过 的依据,

CAS ,虽然大部分情况下, 即使被穿插执行, 但是 值又改回去了,(B穿插执行,修改了value, 这边A会把oldvalue改回去);

这里的 情况不一定会产生bug ;

极端情况:

ABA问题 ,一般不会有什么大问题, 但是某些极端情况 会出现bug ;

解决ABA 问题

  1. 设置 判定的值value 只能往一个方向进行 变化 ; (例如 加就只能加 , 减就只能减)

  2. 如果本来就要有增有减,就引入一个变量 , 版本号 , 每次 value发生改变,就让版本号自增 ;

这样在使用CAS时,就不用直接判断value,而是判断版本号, 看版本号是否有变化 ;

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/11 19:04:33

AI-Trader性能优化:提升AI代理交易速度的10个终极技巧

AI-Trader性能优化:提升AI代理交易速度的10个终极技巧 【免费下载链接】AI-Trader "AI-Trader: 100% Fully-Automated Agent-Native Trading" 项目地址: https://gitcode.com/GitHub_Trending/aitrad/AI-Trader AI-Trader作为100%全自动化的AI代理…

作者头像 李华
网站建设 2026/5/11 19:03:35

2026免费降AI工具测评:5种实用方法教你轻松过AIGC检测

现在写论文,不少人都会用AI辅助找思路、润色语句,确实能省不少功夫。但学校的AI检测系统也在不断升级,要是临近定稿才发现AI率过高,很可能面临延毕的风险,不少同学的检测报告满篇标红,看着都头疼。 很多人第…

作者头像 李华
网站建设 2026/5/11 19:01:36

USB端点描述符避坑指南:搞懂这7个字节,告别设备枚举失败

USB端点描述符避坑实战:7字节配置引发的血泪史 当你的USB设备在电脑上反复弹出"未知设备"提示时,背后往往藏着一个令人抓狂的真相——那看似简单的7字节端点描述符配置错误。我曾花了整整三天追踪一个诡异的数据丢失问题,最终发现只…

作者头像 李华
网站建设 2026/5/11 19:00:45

BaiduPCS-Go终极优化指南:告别百度网盘限速的完整解决方案

BaiduPCS-Go终极优化指南:告别百度网盘限速的完整解决方案 【免费下载链接】BaiduPCS-Go iikira/BaiduPCS-Go原版基础上集成了分享链接/秒传链接转存功能 项目地址: https://gitcode.com/GitHub_Trending/ba/BaiduPCS-Go BaiduPCS-Go是一款基于原版iikira/Ba…

作者头像 李华
网站建设 2026/5/11 19:00:11

手把手复现1G通话:用Python模拟FM调制、FSK信令与FDMA多用户通信

手把手复现1G通话:用Python模拟FM调制、FSK信令与FDMA多用户通信 在移动通信的演进史中,1G系统如同数字时代的罗塞塔石碑,用模拟信号承载了人类首次无线对话的自由。今天我们将穿越回1983年摩托罗拉DynaTAC 8000X面世的年代,用Py…

作者头像 李华
网站建设 2026/5/11 18:59:50

跟着 MDN 学 HTML day_38:(DocumentFragment 文档片段接口详解)

一、什么是 DocumentFragment DocumentFragment 是 DOM 接口中一个非常实用但常常被忽视的特性。它表示一个没有父对象的最小文档对象,可以将其理解为一个轻量版的 Document 对象。与标准的 document 对象类似,DocumentFragment 能够存储由节点组成的文档…

作者头像 李华