CAS 以及它在java中的体现

限于喜欢 提交于 2020-04-13 20:35:17

【今日推荐】:为什么一到面试就懵逼!>>>

Compare And Swap:比较和交换

v(内存位置) 

a(旧的期望值) 

b(改变之后的值)

数据在修改之前,旧的预期值和v中的值一致时,才能修改

 

java中Atomic相关类就是使用的这种算法实现的。 

 

它和Synchronized相对:

Synchoronized属于悲观锁,认为并发数据操作是一个大概率事件(总有刁民想害朕),我操作的时候,得把数据锁上,别人谁也别想动

而CAS属于乐观锁,它认为并发数据操作是小概率事件,你操作数据之后我再核查一遍,现在的数据和我修改的时候,读取的数据是否一致就没事了,通过比较和交换的方式进行数据修改。

 

拿 AtomicInteger 的 incrementAndGet 方法举例,这个方法就是给当前对象的数值+1,但是保证了线程安全:

public void test(){
    AtomicInteger atomicInteger = new AtomicInteger(1);
    atomicInteger.incrementAndGet ();

    Integer integer = 1;
    integer = integer + 1;
    // 以上两种操作,结果是一样的
}

 

看看CAS再JDK1.8中是怎么实现的:

public final int incrementAndGet() {
        // getAndAddInt(this, VALUE, 1) 返回之后进行的 +1 操作
        return U.getAndAddInt(this, VALUE, 1) + 1;
 }
@HotSpotIntrinsicCandidate
public final int getAndAddInt(Object o, long offset, int delta) {
    int v;
    // 不停的去判断,现在的值 和 当时修改时读取的值是否一致
    do {
        // 获取当前变量的值
        v = getIntVolatile(o, offset);
        // offset:内存地址的值
        // v:旧的期望值
        // v + delta :进行内存的数据更新
    } while (!weakCompareAndSetInt(o, offset, v, v + delta));
    // 返回的却是更新前的数值
    return v;
}
// 当前内存存放的值 和 旧的期望值 对比的方法
@HotSpotIntrinsicCandidate
public final boolean weakCompareAndSetInt(Object o, long offset,
                                          int expected,
                                          int x) {
    return compareAndSetInt(o, offset, expected, x);
}
@HotSpotIntrinsicCandidate
public final native boolean compareAndSetInt(Object o, long offset,
                                             int expected,
                                             int x)
// 从内存中获取此对象的值                                        
@HotSpotIntrinsicCandidate
public native int getIntVolatile(Object o, long offset);

看到最后,殊途同归,最后都看到了native这个关键字,进入c的部分,而comparenAndSetInt 通过查阅资源,底层实现的方式大致是:

  1. 判断当前系统是否为多核处理器;

  2. 执行 CPU 指令 cmpxchg,如果为多核则在 cmpxchg 加 lock 前缀。

可以清晰的看出,java中的cas是通过底层cpu命令实现对比和交换,通过cpu实现无锁自增。

 

优点:

    1、它属于cpu指令级操作,速度很快

    2、没有线程阻塞带来的性能消耗问题

缺点:

    1、无法通过它进行并发控制

    2、ABA问题:判断的时候,虽然当前值和预期值一致,但是可能是由于其他线程改修数据之后又修改回来,这个时候就不严谨了(这已经不是当初的那个它了)解决此类问题,可以通过添加一个时间戳来解决。

 

有什么不足欢迎大家指出和交流!

 

 

发布了223 篇原创文章 · 获赞 301 · 访问量 11万+
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!