java CAS原理分析

java CAS原理分析

基本过程分析

在并发中,锁是最简单的方式,但是代价也是很高昂的。无锁算法一直是技术人员的最大追求,java中cas(compareAndSet)是著名的无锁算法。
AtomicInteger为例,使用其方法有两个参数,一个是预期的旧值expect,另一个是要更新的值update,当且仅当预期的旧值expect和当前真实的值一致时,将内存值修改为update,否则什么都不做返回false。

进入到AtomicInteger 类中,有private volatile int value; 这个能够保证数据在多线程中可见,在前一篇文章中已经讲到过了。打开看compareAndSet方法,

     public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

会发现调用unsafe.compareAndSwapInt(this, valueOffset, expect, update);这个方法,该方法声明为public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);是一个native的方法。到这里基本明白了,这是借助了JNI调用CPU的cas指令,只有一步原子操作,因此非常快。

再看看getAndSet方法:

    public final int getAndSet(int newValue) {
        for (;;) {
            int current = get();
            if (compareAndSet(current, newValue))
                return current;
        }
    }

主要还是依靠CAS操作,不过加入了重试机制,直到成功为止。

可能存在的问题

CAS带来两个常见的问题:

1.ABA的问题,如线程1检查操作值A,需要和预期值相等的情况设置为Y,这时候线程2也取出操作值A,然后赋值为B,接着又把B改回成A,这时候线程1进行CAS操作的时候发现得到的值还是A,然后接着进行操作,这其实有一些问题,在线程1取值和操作之间发生了翻天覆地的变化,虽然最终结果一致,但是不代表没有问题。解决这个问题通用的解决方法是弄一个版本号(version),如1A-2B-3A这样来区分,想起来以前在实验室实现的一个带版本号的算法了。

2.CAS操作中有很多重试的机制,如getAndSet(newValue);不成功的时候会返回重试,直到成功为止,如果并发竞争较多,经常导致重试,其实开销会很大。因为其中有volatile修饰的变量,根据之前讲的volatile的底层原理,编译后会有lock前缀的内存屏障指令,会锁住缓存区域,之后会使所有的其他CPU的对应缓存失效,这个代价是比较高的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值