CAS与AQS
CAS :乐观锁,通过UnSafe类实现。更新时会比较原数据(例如:版本号等),发现版本号有变动则更新失败,否则更新成功。
AQS:AbstructQueuedSynchronzer,抽象队列同步器,只是一个框架,维护state状态,多线程争取state状态,为争取到的线程进入队列等待。
AtomicInteger和AtomicLong
不能既比较值又比较版本号,所以借助一个内部类Pair来比较版本号
Unsafe的CAS
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
AtomicInteger中的运用
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
对照着看参数含义
参数 | 含义 |
---|---|
Object var1 | 需要修改的对象 |
long var2 | 对象里面要修改的值的偏移量 |
int var4 | 原来值的大小 |
int var5 | 更新后值的大小 |
AtomicBoolean和AtomicReference
AtomicStampedReference和AtomicMarkableReference
AtomicStampedReference为了解决ABA问题,在比较值的同时,还会比较版本号。
AtomicMarkableReference和AtomicStampedReference原理差不多,只是版本号为boolean类型,因此并不能完全解决ABA问题
AtomicIntegerFieldUpdater、AtomicBooleanFieldUpdater、AtomicReferenceFieldUpdater
用于无法修改的(第三方)类的Atomic操作
@CallerSensitive
public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,
String fieldName) {
return new AtomicIntegerFieldUpdaterImpl<U>
(tclass, fieldName, Reflection.getCallerClass());
}
U为第三方类,fielName为该类里面的需要修改的那个成员变量。
限制条件:修改的字段不能是包装类,比如Integer、Double,且必须volatile修饰。结论:比较鸡肋
Striped64与LongAdder
jdk1.8新增了增对long类型的原子操作LongAdder、LongAccumulator;针对double类型的原子操作DoubleAdder、DoubleAccumulator
四个类都继承Striped64
LongAdder
原理:未解决cas并发不足的缺点,把单个数分成多个片段call[],累加时各个片段各自加各自的,取值时对各个片段汇总。取值和累加并不互斥,所以只保证最终一致性,对于一些数据敏感的业务还是不能取代Atomic类
LongAccumulator
原理:与LongAdder差不多,比LongAdder更强大,支持初始化大小,LongAdder为0。LongAccumulator可自己定义二元操作符