java并发:CAS算法和ABA问题

CAS算法是硬件对于并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令。

CAS用于管理对共享数据的并发访问。

java的并发包中,AQS、原子操作类等都是基于CAS实现的。

CAS 是一种 无锁的 非阻塞算法的 实现。

CAS(Compare-And-Swap),简单来说就是比较和替换。

比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替换当前变量的值。

比如说,想使用一台机器,先通过比较判断这台机器是否处于未占用状态,如果机器处于未占用状态,就将它设为使用状态。


CAS 包含了三个操作数:
需要读写的内存值: V,进行比较的预估值: A,拟写入的更新值: B。
当且仅当 V == A 时, V = B, 否则,将不做任何操作;

 

以下用同步锁synchronized模拟CAS 算法。

注意:真正的CAS算法是无锁的。

如下:

public class CasDemo {
    public static void main(String[] args) {
        final CompareAndSwap cas = new CompareAndSwap();

        for(int i=0; i<10; i++){
            // 创建10个线程,模拟多线程环境
            new Thread(new Runnable(){
                @Override
                public void run(){
                    int expectedValue = cas.get();

                    boolean b = cas.compareAndSwap(expectedValue, (int)(Math.random()*5));
                }
            }).start();
        }
    }


    static   class  CompareAndSwap{
         private  int value;

        // 获取内存值
         public synchronized  int get() {
             return  value;
         }

         // 比较当前值和期望值,相同就替换。
         public  synchronized  boolean compareAndSwap(int expectedValue,int newValue) {
             //获取旧值
             int oldValue=value;
             if(oldValue==expectedValue) {
                    this.value=newValue;
                    System.out.println(Thread.currentThread().getName()+"比较当前值和期望值,结果一致,将其替换为新值。");
                    return true;
             }
             System.out.println(Thread.currentThread().getName()+"比较当前值和期望值,结果不一致,不替换为新值");
             return  false;
         }
    }
}

 

ABA问题:

尽管CAS看起来没问题,其实存在一个逻辑漏洞。

如果一个变量V初次读取时是A值,并且在赋值时检查到它仍然是A值,那么我们就能说它的值没有改变过吗?

如果在此期间,它的值曾经改成了B,后来又改回为A。那么CAS操作就会误以为它从来没有改变过。

这个称为CAS的“ABA”问题。

当然,在大部分情况下ABA问题并不会影响程序并发的正确性。如果需要解决ABA问题,可以改用传统的互斥同步。

 

posted on 2018-08-09 17:15  乐之者v  阅读(875)  评论(0编辑  收藏  举报

导航