【多线程】CAS的应用 | CAS的概念 | 实现原子类 | 实现自旋锁

2024-04-22 04:04

本文主要是介绍【多线程】CAS的应用 | CAS的概念 | 实现原子类 | 实现自旋锁,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 一、CAS
          • 1.什么是CAS
          • 2.实现原子类
          • 3.实现自旋锁


一、CAS

1.什么是CAS

Compare and swap 比较并交换。

比较交换的是 内存 和 寄存器

比如此时有一个内存 : M。 还有两个寄存器A,B

​ CAS ( M , A , B ) :如果M和A的值相同的话,就把M和B的值进行交换(交换的目的是为了把B赋值给M,M = B),同时整个操作返回 true。如果M和A的值不同的话,无事发生,同时整个操作返回false。

//伪代码:
boolean CAS(address, expectValue, swapValue) {if (&address == expectedValue) {&address = swapValue;return true;}return false;
}
  • CAS其实是一个CPU指令,一个CPU指令,就可以完成上述比较交换的逻辑。
  • 单个的CPU指令是原子的。所以可以使用CAS来完成一些操作来代替“加锁”。为编写线程安全的代码提供了线的思路,基于CAS实现线程安全的方式,也叫“无锁编程”。

优点:保证线程安全,同时避免发生阻塞。

缺点:代码可读性差,并且只能适用在特定场景,不如加锁普适。

​ CAS本质上是CPU提供的指令,被操作系统封装后,提供成为APi。又再次被JVM进行封装,提供成API,最终由程序员调用方法实现操作。

2.实现原子类

之前int count++的操作,就不是原子的(load,add,save)

在Java标准库中,提供了原子类,例如AtomicInteger,基于CAS的方式对int进行封装,++就封装成原子操作了。

    public static AtomicInteger count = new AtomicInteger(0);//对int进行原子化包装//0作为构造方法的参数public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{for (int i = 0; i < 50000; i++) {count.getAndIncrement();//count++; 后置++
//                count.incrementAndGet();//++count  前置++
//                count.getAndDecrement();//count--; 后置--;
//                count.decrementAndGet();//--count 前置--}});Thread t2 = new Thread(()->{for (int i = 0; i < 50000; i++) {count.getAndIncrement();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}

在Java中,有些操作是偏底层的操作,在使用时有着更多的注意事项,稍有不慎就容易写出问题。这些操作就同一放在unsafe这个类中

在这里插入图片描述

//伪代码
class AtomicInteger {private int value;//相当于内存public int getAndIncrement() {int oldValue = value;//oldValue相当于寄存器    while ( CAS(value, oldValue, oldValue+1) != true) {//CAS(内存,寄存器A,寄存器B)oldValue = value;}return oldValue;}
}

寄存器A先保存当前内存的值,CAS来判断此时有没有被穿插执行。如果没有穿插执行,内存的值等于寄存器A的值,把寄存器B(B执行+1操作)的值赋值给内存,同时CAS返回的是true,循环不成立,返回是是自增前的值。

如果被穿插执行了,CAS中,内存的值不等于寄存器A的值,CAS直接返回false.此时循环成立,将被穿插执行过的内存值,重新赋值给寄存器A,也就是说要再读一遍内存。再次执行CAS。

线程不安全的本质是进行操作的过程中,穿插执行。

1.加锁是通过阻塞的方式,避免穿插。

2.CAS是通过重试的方式,避免穿插。如果值和之前不相等了,重新更新一下,在进行操作。

3.实现自旋锁
//伪代码:
public class SpinLock {private Thread owner = null;//记录当前这个锁被哪个线程获取到。 null表示未加锁public void lock(){//加锁// 通过 CAS 看当前锁是否被某个线程持有. // 如果这个锁已经被别的线程持有, 那么就自旋等待. // 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程. while(!CAS(this.owner, null, Thread.currentThread())){}}public void unlock (){//解锁this.owner = null;}
}
  • while循环中,CAS判断当前owner是不是未加锁状态。如果是未加锁的,就把owner赋值成 Thread.currentThread())(调用lock方法的线程引用)进行加锁。如果已经被加锁了,CAS返回false,取反之后,while就会反复执行。一旦其他线程释放了这个锁,owner变成null时,因为while不停循环,就会立即拿到当前这把锁。

缺点:while循环在忙等的过程中,不断消耗CPU资源。如果加锁的概率不大,付出的CPU资源就是值得的。如果当前的锁冲突很激烈,可能会拿不到,此时自旋锁就不适用了。

点击移步博客主页,欢迎光临~

偷cyk的图

这篇关于【多线程】CAS的应用 | CAS的概念 | 实现原子类 | 实现自旋锁的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/924780

相关文章

Flutter实现文字镂空效果的详细步骤

《Flutter实现文字镂空效果的详细步骤》:本文主要介绍如何使用Flutter实现文字镂空效果,包括创建基础应用结构、实现自定义绘制器、构建UI界面以及实现颜色选择按钮等步骤,并详细解析了混合模... 目录引言实现原理开始实现步骤1:创建基础应用结构步骤2:创建主屏幕步骤3:实现自定义绘制器步骤4:构建U

SpringBoot中四种AOP实战应用场景及代码实现

《SpringBoot中四种AOP实战应用场景及代码实现》面向切面编程(AOP)是Spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护,在SpringBoot应用中,AO... 目录引言场景一:日志记录与性能监控业务需求实现方案使用示例扩展:MDC实现请求跟踪场景二:权限控制与

Android实现定时任务的几种方式汇总(附源码)

《Android实现定时任务的几种方式汇总(附源码)》在Android应用中,定时任务(ScheduledTask)的需求几乎无处不在:从定时刷新数据、定时备份、定时推送通知,到夜间静默下载、循环执行... 目录一、项目介绍1. 背景与意义二、相关基础知识与系统约束三、方案一:Handler.postDel

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义