什么是CAS算法

CAS(比较和设置)算法是硬件对于并发操作的实现.(CPU指令级的操作,只有一步原子操作) 无锁的非阻塞算法  CAS算法保证同时访问时只有一个线程能进来,当多个线程同时并发访问操作共享数据的时候,有且只有一个能够成功,其他的线程都会失败,会尝试当前操作直到没有冲突为止..CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B.当且仅当预期值阿和内存值V相同时,将内存值V修改为B,否则什么都不做。类似于乐观锁。CAS自旋的概率会比较大,从而浪费更多的CPU资源。

CAS的缺点

1.CPU开销较大

在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很大的压力。

2.不能保证代码块的原子性(多个变量)

CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用Synchronized了。

3.ABA问题

这是CAS机制最大的问题所在。

什么是ABA问题?

引用原书的话:如果在算法中的节点可以被循环使用,那么在使用“比较并交换”指令就可能出现这种问题,在CAS操作中将判断“V的值是否仍然为A?”,并且如果是的话就继续执行更新操作,在某些算法中,如果V的值首先由A变为B,再由B变为A,那么CAS将会操作成功。但是多数的场景(比如高效的计数器实现)是不用担心这个问题的

怎么避免ABA问题?

Java中提供了AtomicStampedReference和AtomicMarkableReference来解决ABA问题。 

 

JDK如何实现CAS操作

我们接下来看看JDK自带的原子类的AtomicInteger的源码,下面贴出关键代码

private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
 
static {
    try {
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception ex) { throw new Error(ex); }
}
 
private volatile int value;

首先可以看到AtomicInteger类在域中声明了这两个私有变量unsafe和valueOffset。其中unsafe实例采用Unsafe类中静态方法getUnsafe()得到,但是这个方法如果我们写的时候调用会报错,因为这个方法在调用时会判断类加载器,我们的代码是没有“受信任”的,而在jdk源码中调用是没有任何问题的;valueOffset这个是指类中相应字段在该类的偏移量,在这里具体即是指value这个字段在AtomicInteger类的内存中相对于该类首地址的偏移量。

然后可以看一个有一个静态初始化块,这个块的作用即是求出value这个字段的偏移量。具体的方法使用的反射的机制得到value的Field对象,再根据objectFieldOffset这个方法求出value这个变量内存中在该对象中的偏移量。

public final int incrementAndGet() {
        for (;;) {
            int current = get(); //获取当前变量最新值
            int next = current + 1;
            if (compareAndSet(current, next))
                return next;
        }
}

public final boolean compareAndSet(int expect, int update) {
//第一个参数为需要改变的对象,第二个为偏移量(即之前求出来的valueOffset的值),
   return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

incrementAndGet()方法实现了自增的操作。核心实现是先获取当前值和目标值(也就是值+ 1),如果compareAndSet(current,next)返回成功则该方法返回目标值。

那么compareAndSet是做什么的呢?

理解这个方法我们需要引入CAS操作AtomicInteger中的CAS操作就是compareAndSet(),其作用是每次从内存中根据内存偏移量(valueOffset)取出数据,将取出的值跟望比较,如果数据一致就把内存中的值改为更新。

这样使用CAS就保证了原子操作。其余几个方法的原理跟这个相同。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值