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问题,可以改用传统的互斥同步。