CAS 的解释

CAS

全名 compare and swap

CAS 解决了什么问题?

public class{
  	public static void main(String[] args){
    		new Thread(() -> {
            Counter.count++;
        }, "thread-1").start();

        new Thread(() -> {
            Counter.count++;
        }, "thread-2").start();
  	}
  	
  	public static class Counter{
      	public static int count = 0;
    }
}

Counter.count++ 包括三个步骤

  1. 读取 Counter.count 的值
  2. 计算 Counter.count 加 1 后的值
  3. Counter.count 赋值为计算后的值

以下是有可能出现的执行顺序

在这里插入图片描述

可以看到,进行了两次 +1 但是从结果来看只加了一次

究其原因,是因为操作的值,在我们读之后,写之前,这个空窗期产生了变化,但是这个变化被忽视了

CAS 怎么解决的问题

首先,问题的产生是因为,忽视了空窗期值的变化,那不忽略就得了呗,最终赋值的时候检查下变没变

Unsafe 中的 cas 方法

// var1 是要修改的对象
// var2 是要修改的变量的内存偏移量,由 var1 和 var2 可以得到变量的内存地址
// var4 要加上的值
public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        var5 = this.getIntVolatile(var1, var2); // 获取旧值
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
	   // compareAndSwapInt native 方法,成功返回 true
  	   // var1 + var2 可以得到变量的最新值,
  	   // 然后和旧值(var5) 比较,如果相等,把计算后的值(var5 + var4)写入到变量的内存地址中
    return var5;
}

ABA 问题

由于我们只是比较值是否和读的时候一致,那就有可能读到 A 之后,然后变为 B ,在比较的时候又变成 A,

这个问题的解决方法是给数据加上版本号,不仅比较值,还比较版本号。

数据的值数据的值
A1.0
B2.0
A3.0

最后

cas 的优点是避免线程阻塞唤醒的开销,但是在极端情况下,会一直自旋(一直在while中循环),适合写少读多的情况

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值