Java深入学习02:CAS 算法以及低层原理

参考文章:https://www.cnblogs.com/linkworld/p/7819270.html;已经描述很清晰

 

i++ 的原子性问题

  1. i++的操作实际上分为三个步骤: "读-改-写";
  2. 原子性: 就是"i++"的"读-改-写"是不可分割的三个步骤;
  3. 原子变量: JDK1.5 以后, java.util.concurrent.atomic包下,提供了常用的原子变量;
    • 原子变量中的值,使用 volatile 修饰,保证了内存可见性;
    • CAS(Compare-And-Swap) 算法保证数据的原子性;
int i = 10;
i = i++;  // 此时, i=10

执行步骤:
int temp = i;
i = i + 1;
i = temp;


// 测试类
public class TestAtomicDemo{
    public static void main(String[] args){

        AtomicDemo ad = new AtomicDemo();

        for(int i=0; i < 10; i++){
            new Thread(ad).start();
        }
    }
}

class AtomicDemo implements Runnable{
    private int serialNumber = 0;

    public void run(){

        try{
            Thread.sleep(200);
        }catch(InterruptedException e){

        }

        System.out.println(Thread.currentThread().getName() + ":" + getSerialNumber());
    }

    public int getSerialNumber(){
        return serialNumber++;
    }
}

 

// 改进: 使用原子变量
class AtomicDemo implements Runnable{

    private AtomicInteger serialNumber = new AtomicInteger();

    public void run(){
        try{
            Thread.sleep(200);
        }catch(InterruptedException e){

        }

        System.out.println(Thread.currentThread().getName()+":"+getSerialNumber());
    }

    public int getSerialNumber(){
        // 自增运算
        return serialNumber.getAndIncrement();
    }
}

 

CAS 算法

  • CAS(Compare-And-Swap) 算法是硬件对于并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,用于
    管理对共享数据的并发访问;
  • CAS 是一种无锁的非阻塞算法的实现;
  • CAS 包含了三个操作数:
    • 需要读写的内存值: V
    • 进行比较的预估值: A
    • 拟写入的更新值: B
    • 当且仅当 V == A 时, V = B, 否则,将不做任何操作;
// 模拟CAS 算法
class CompareAndSwap{
    private int value;

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

    // 无论更新成功与否,都返回修改之前的内存值
    public synchronized int compareAndSwap(int expectedValue, int newValue){
        // 获取旧值
        int oldValue = value;

        if(oldValue == expectedValue){
            this.value = newValue;
        }

        // 返回修改之前的值
        return oldValue;
    }

    // 判断是否设置成功
    public synchronized boolean compareAndSet(int expectedValue, int newValue){
        return expectedValue == compareAndSwap(expectedValue, newValue);
    }
}

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

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

                    boolean b = cas.compareAndSet(expectedValue, (int)(Math.random()*100));
                    System.out.println(b);
                }
            }).start();
        }
    }
}

CAS优点

  1- 避免优先级倒置和死锁等危险,竞争比较便宜,协调发生在更细的粒度级别,允许更高程度的并行机制等。

 

CAS缺点 

  1- 循环时间长CPU开销很大;

  2- 只能保证一个共享变量的原子性

  3- 引出了ABA问题

 

CAS算法底层原理

 

 

  我们以AtomicIntegerd 的getAndIncrement方法为例,进行简要分析。

##AtomicInteger类

    private static final Unsafe unsafe = Unsafe.getUnsafe();

    private static final long valueOffset;//AtomicInteger 对象 value 属性偏移地址

    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }


##Unsafe类
    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

    @CallerSensitive
    public static Unsafe getUnsafe() {
        Class var0 = Reflection.getCallerClass();
        if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
            throw new SecurityException("Unsafe");
        } else {
            return theUnsafe;
        }
    }


public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

 

posted on 2019-11-08 09:15  我不吃番茄  阅读(600)  评论(0编辑  收藏  举报