原子类Atomic
阅读原文时间:2023年07月08日阅读:2

非阻塞算法:如果在某种算法中,一个线程的失败或挂起不会导致其他线程也失败或挂起,那么这种算法就被称为非阻塞算法。如果在算法的每个步骤中都存在某个线程执行下去,那么这种算法也被称为无锁(Lock_Free)算法。

原子变量类是Java为支持非阻塞算法而提供的对象。原子变量比锁的粒度更细,并发性能更好,通常在并发场景下进行变量的复合操作时使用,如:i++、if..get等

  • 基本数据类:AtomicBoolean、AtomicInteger、AtomicLong

  • 引用对象类:AtomicReference

  • 数组类:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray

  • 属性更新类:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater

  • 解决ABA问题的类:AtomicStampedReference、AtomicMarkableReference

  • 说明:CAS包含了3个操作数:需要读写的内存位置V,进行比较的值A、待更新的值B,当且仅当V的值等于A时,通过原子方式更新V的值为B;当多个线程使用CAS同时更新同一个变量时,只有其中的一个线程能更新成功,其他线程都将失败,失败的线程不会阻塞。

  • 应用场景:Java提供的原子变量类中的复合操作底层均通过CAS技术实现原子操作。

  • 源码分析(以AtomicInteger#getAndIncrement()为例)

    //i++的原子操作
    public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
    }

    public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
    //获取内存中共享变量var1的值
    var5 = this.getIntVolatile(var1, var2);
    //执行底层CAS操作:var1内存位置,var2本地缓存的值,var5共享内存中的值,当且仅当var2=var5时,var1的值更新为var5+var4
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;

    }

  • 问题描述:ABA问题是一种异常现象——如果在算法中的节点可以被循环使用,那么在使用CAS时就可能出现这个问题。如线程1和2同时将变量X的值由A更新为B,线程1先将变量X的值由A改为C再改为A,此时线程2执行CAS更新变量X的值,发现变量X的值是没有变化的,但实际变量X的值已经发生过变化。

  • 解决方案:引入一个变量——版本号,更新时需更新变量的值和版本号。如原子变量类AtomicStampedReference、AtomicMarkableReference。