Cas的基本原理

什么是CAS

在Java中,CAS是指"比较并交换"(Compare and Swap)操作.由于他是一个原子类操作在cpu上只有一条指令.他是一种多线程同步机制,用于实现非阻塞算法和并发控制.CAS包含三个变量:内存地址 value,寄存器上旧的值oldvalue,以及新的值B.

以AtomicInteger为例CAS的操作流程是:

  1. 将当前内存地址中的值value与寄存器中的值oldvalue进行比较
  2. 如果相等将新的值oldvalue+1的值赋给oldvalue并返回.
  3. 如果不等,进入循环将新的的value赋给oldvalue,再一次进行判断.

这样就可以判断在当前变量自增的时候是否有其他线程穿插进来了

在Java中,Java.util.concurrent包提供了一些原子类用于支持CAS操作.这些原子类提供了CAS的封装,可以直接使用他们来实现线程安全操作.

CAS引发的ABA问题

虽然CAS操作是一种无锁的并发控制装置,但并不适合所有的场景.在高并发的场景下多个线程频繁的征用一个CAS操作可能会导致ABA问题.进而引发不一致性.

举个栗子:

滑稽老哥 有 100 存款. 滑稽想从 ATM 取 50 块钱. 取款机创建了两个线程, 并发的来执行 -50操作.我们期望一个线程执行 -50 成功, 另一个线程 -50 失败.如果使用 CAS 的方式来完成这个扣款过程就可能出现问题.

正常的过程

  1. 存款 100. 线程1 获取到当前存款值为 100, 期望更新为 50; 线程2 获取到当前存款值为 100, 期 望更新为 50.
  2. 线程1 执行扣款成功, 存款被改成 50. 线程2 阻塞等待中.
  3. 轮到线程2 执行了, 发现当前存款为 50, 和之前读到的 100 不相同, 执行失败.

异常的过程

  1. 存款 100. 线程1 获取到当前存款值为 100, 期望更新为 50; 线程2 获取到当前存款值为 100, 期 望更新为 50.
  2. 线程1 执行扣款成功, 存款被改成 50. 线程2 阻塞等待中.
  3. 在线程2 执行之前, 滑稽的朋友正好给滑稽转账 50, 账户余额变成 100 !!)轮到线程2 执行了, 发现当前存款为 100, 和之前读到的 100 相同, 再次执行扣款操作

这个时候, 扣款操作被执行了两次!!! 都是 ABA 问题搞的鬼!!

**解决方案 **

给要修改的值, 引入版本号. 在 CAS 比较数据当前值和旧值的同时, 也要比较版本号是否符合预期. CAS 操作在读取旧值的同时, 也要读取版本号.

真正修改的时候,

如果当前版本号和读到的版本号相同, 则修改数据, 并把版本号 + 1.

如果当前版本号高于读到的版本号. 就操作失败(认为数据已经被修改过了).

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值