工程建设信息网站接口,网站内容保护,网站制作公司 全贵州,秦皇岛建设网站官网CAS#x1f50e;什么是CAS#x1f50e;伪代码解析#x1f50e;CAS是如何实现原子性的#x1f50e;CAS的应用#x1f33b;实现原子类#x1f33b;实现自旋锁#x1f50e;ABA问题#x1f33b;ABA问题可能引起的BUG#x1f33b;ABA问题的解决方案#x1f50e;结尾#…
CAS什么是CAS伪代码解析CAS是如何实现原子性的CAS的应用实现原子类实现自旋锁ABA问题ABA问题可能引起的BUGABA问题的解决方案结尾什么是CAS
CAS 全称Compare and swap(比较并交换)
解释 寄存器A的值和内存B的值进行比较,如果值相同,就把寄存器C的值和内存B的值进行交换 伪代码解析
boolean CAS(address, expectValue, swapValue) {if (address expectedValue) {address swapValue;return true;}return false;
}
解释 if ( address expectedValue) 如果寄存器A的值和内存B的值相等
address swapValue 将寄存器C的值与内存B的值交换
注意 上述代码只是伪代码,用来理解CAS的执行过程 针对上述代码,多线程情况下可能会引起安全问题 而CAS是原子性的,故不会引起安全问题 CAS是如何实现原子性的
基于硬件(CPU)实现的原子性 CAS的应用
实现原子类
基于 java.util.concurrent.atomic 包中的类 一个典型的代表就是 AtomicInteger 类
举个栗子
public static void main(String[] args) throws InterruptedException {AtomicInteger num new AtomicInteger(0);int n 50_000;Thread t1 new Thread(() - {for (int i 0; i n; i) {//numnum.getAndIncrement();}}, t1线程);Thread t2 new Thread(() - {for (int i 0; i n; i) {//numnum.getAndIncrement();}}, t2线程);t1.start();t2.start();t1.join();t2.join();System.out.println(num);}针对上述代码 如果是非原子的自增操作(num),就可能存在线程安全问题 但是由于CAS本身就是原子的,所以不会存在线程安全问题
也就是说,CAS操作可以不用加锁就能够解决线程安全问题 实现自旋锁
伪代码解析
public class SpinLock {private Thread owner null;public void lock(){// 通过 CAS 看当前锁是否被某个线程持有. // 如果这个锁已经被别的线程持有, 那么就自旋等待. // 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程. while(!CAS(this.owner, null, Thread.currentThread())){}}public void unlock (){this.owner null;}
}解释
Thread owner null 代表当前的锁没有被线程持有
while(!CAS(this.owner, null, Thread.currentThread())) Thread.currentThread() 代表当前线程 null 代表空 this.owner 代表当前锁
如果当前 owner 是null,就把当前线程的引用设置到 owner(加锁),循环结束
如果当前 owner 不是null,代表已经有其他线程加锁成功 此时就一直进行循环比较,不停的尝试加锁(速度很快)
public void unlock () 代表解锁 this.owner null 解锁就是将owner设为null ABA问题
什么是ABA问题
通俗点来说就是从A变成了B最后又变成了A A–B–A
CAS是对比内存和寄存器中的值,查看是否相同 (通过对比,判断内存中的值是否改变过)
但是对比时发现内存中的值是相同的,也不能确定内存中的值就没发生过改变
解释 t1线程读取内存中的值时,t2线程将内存中的值从A变成了B最后又变成了A 这时t1线程读取到的内存的值仍然是A,但是内存的值却发生了变化 这就是ABA问题
举个栗子
我们买手机的时候 可能买到的是原装手机(没有更改的) 也可能买到的是翻新机—别人用了很久的,然后手机厂商进行一系列操作(换个壳,去去尘等),这样的手机看起来虽然和原装的没太大区别,但终究也只是看起来
原装手机就类似与内存中的值没有发生过改变 翻新机就类似于A–B–A ABA问题可能引起的BUG
举个栗子
滑稽老哥去ATM机取款50元,他的银行账户有100元,取款之后变为50元 ATM并发执行两个线程 (1)线程1获取到当前存款为100元,执行扣款50元 线程2获取到当前存款为100元,执行扣款50元 (2)线程1执行扣款成功,滑稽老哥存款变为50 线程2阻塞等待 (3)此时正好滑稽老哥的朋友向滑稽老哥转账50元请滑稽老哥帮买东西 (4)滑稽老哥的存款又变为了100元 (5)线程2执行,发现存款仍为100元,执行扣款50元,此时滑稽老哥的账户又被扣款了50元 ABA问题的解决方案
引入版本号,规定版本号只能增加 每次CAS对比的时候,不仅需要对比数值,而且需要对比版本号 如果进行修改数值,就将版本号1
这样再去对比ABA问题时 发现版本号已经发生改变,就证明数值发生了变化 发现版本号没有发生改变,证明数值没有发生变化
举个栗子
滑稽老哥去ATM机取款50元,他的银行账户有100元,取款之后变为50元 ATM并发执行两个线程,此时引入版本号,版本号为0 (1)线程1获取到当前存款为100元,执行扣款50元 线程2获取到当前存款为100元,执行扣款50元 (2)线程1执行扣款成功,滑稽老哥存款变为50 线程2阻塞等待,版本号变为1 (3)此时正好滑稽老哥的朋友向滑稽老哥转账50元请滑稽老哥帮买东西,版本号变为2 (4)滑稽老哥的存款又变为了100元 (5)线程2执行,发现存款仍为100元,但版本号发生了改变,此时就会执行失败 (6)滑稽老哥成功保住了50元 结尾 创作不易,如果对您有帮助,希望您能点个免费的赞 大家有什么不太理解的可以私信或者评论区留言一起加油