CAS

CAS 全称 Compare And Swap,即内存中的值V,旧的值A,预期的值B,当且仅当内存值V的值等于旧的值A时才会将内存值V的值修改为B,否则放弃替换;

CAS 底层使用 lock cmpxchg 指令(X86架构) ● 原子整数 ● 原子引用 ● 原子数组 ● 字段更新器 ● 原子累加器 ● Unsafe

原理

通过调用 Unsafe 类 compareAndSwapXXX 方法实现,该方法为本地方法,方法有4个参数(对象、对象地址、预期的值、修改的值)

缺点

  1. ABA的问题
  2. 自旋时间过长;
  3. 只能保证一个共享原子操作;

    ABA的问题

    CAS操作可能带来ABA问题,因为CAS操作需要在操作值的时候,检查值有没有发生变化,如果没有发发生变化则更新。如果一个值原理是A,变成了B,又变成了A,那么使用CAS进行检查时会认为它的值没有变化,但是实际上却变了。
    ABA问题的解决办法就是使用版本号,在变量前面追加版本号,每次变量更新时把版本号加1,那么A-B-A就会变成1A-2B-3A。
    从jdk1.5开始,jdk中的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法的作用首先检查当前引用是否等于预期引用,并且检查当前标志是否等于预期标志,如果都相等,则以原子方式将该引用和标志的值设为给定的更新值。

    原子整数

  • AtomicInteger
  • AtomicBoolean
  • AtomicLong

    AtomicInteger

    private volatile int value
    使用 volatile 关键字修饰,默认初始值为 0;
方法 功能
set(int newValue) 设置新值
get() 获取当前的值
getAndAdd(int delta) 先获取值,再增加值
addAndGet(int delta) 先增加值,再获取值
incrementAndGet() 先自增1,再返回自增后的数据
getAndIncrement() 先返回当前的数据,再自增1
decrementAndGet() 先自减1,再返回自减后的数据
getAndDecrement() 先返回当前数据
compareAndSet(int expect, int update) 通过前值和更新值更新数据
updateAndGet(IntUnaryOperator updateFunction) 更新值,再获取
(updateFunction是一个入参的lambda表达式)
accumulateAndGet(int x, IntBinaryOperator accumulatorFunction) x值和旧值做一个运算,这个运算是accumulatorFunction(accumulatorFunction是两个入参的lambda表达式)

原子引用类型

  • AtomicReference
  • AtomicStampedReference:通过加版本号解决ABA的问题;
  • AtomicMarkableReference:通过值是否被改变解决ABA的问题;

    原子数组

    保证数组元素的线程安全

  • AtomicIntegerArray

  • AtomicLongArray
  • AtomicReferenceArray

    字段更新器

    利用字段更新器,可以针对对象的某个域(Field)进行原子操作,只能配合 Volatile 修饰的字段使用,否则出现参数异常错误;

  • AtomicReferenceFieldUpdater

  • AtomicIntegerFieldUpdater
  • AtomicLongFieldUpdater

    1. // Student.class 表示对哪个类保证原子操作
    2. // String.class 表示对哪个属性类型保证原子操作
    3. // "name" 表示对哪个属性名称保证原子操作
    4. AtomicReferenceFieldUpdater<Student, String> updater =
    5. AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class, "name");

    原子累加器

  • LongAdder

  • DoubleAdder

    LongAdder

    1. // 累加单元数组,懒惰初始化
    2. transient volatile Cell[] cells;
    3. // 基础值,如果没有竞争,则用 cas 累加这个域
    4. transient volatile long base;
    5. // 在 cells 创建或者扩容时,置为1,表示加锁
    6. transient volatile int cellsBusy;

    Unsafe

    1. // 获取 Unsafe 对象
    2. Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
    3. theUnsafe.setAccessible(true);
    4. Unsafe unsafe = (Unsafe) theUnsafe.get(null);

    通过Unsafe对象执行CAS操作

    ```java package top.simba1949.app2;

import sun.misc.Unsafe; import java.lang.reflect.Field;

/**

  • @author Anthony
  • @date 2020/10/28 15:45 */ public class Application {

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

    1. Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
    2. theUnsafe.setAccessible(true);
    3. Unsafe unsafe = (Unsafe) theUnsafe.get(null);
    4. // 获取域的偏移量地址
    5. long idOffset = unsafe.objectFieldOffset(User.class.getDeclaredField("id"));
    6. long nameOffset = unsafe.objectFieldOffset(User.class.getDeclaredField("name"));
    7. User user = new User();
    8. // 执行 CAS 操作
    9. unsafe.compareAndSwapInt(user, idOffset, 0, 1);
    10. unsafe.compareAndSwapObject(user, nameOffset, null, "张三");
    11. System.out.println(user.toString());

    } }

class User{ volatile int id; volatile String name; // 省略getter/setter 和 toString 方法 } ```