1.CAS的实现
2.CAS的特点
3. 原子更新基本类型
atomic 包提高原子更新基本类型的工具类,主要有这些:
AtomicBoolean:以原子更新的方式更新 boolean;
**AtomicInteger:**以原子更新的方式更新 Integer;
AtomicLong:以原子更新的方式更新 Long;
这里以 AtomicInteger 为例总结常用的方法
1.incrementAndGet() :以原子的方式将实例中的原值进行加 1 操作,并返回最终相加后的结果;
2.getAndIncrement():以原子的方式将实例中的原值加 1,返回的是自增前的旧值;
3.addAndGet(int delta) :以原子方式将输入的数值与实例中原本的值相加,并返回最后的结果;
4.getAndSet(int newValue):将实例中的值更新为新值,并返回旧值;
4. 原子引用
AtomicReference:原子更新引用类型;
主线程仅能判断出共享变量的值与最初值 A 是否相同,不能感知到这种从 A 改为 B 又 改回 A 的情况,如果主线程希望:只要有其它线程【动过了】共享变量,那么自己的 cas 就算失败,这时,仅比较值是不够的,需要再加一个版本号;
AtomicMarkableReference:原子更新引用类型,这种更新方式会带有版本号。而为什么在更新的时候会带有版本号,是为了解决 CAS 的 ABA 问题;
AtomicStampedReference 可以给原子引用加上版本号,追踪原子引用整个的变化过程,如: A -> B -> A ->C ,通过AtomicStampedReference,我们可以知道,引用变量中途被更改了几次。但是有时候,并不关心引用变量更改了几次,只是单纯的关心是否更改过,所以就有了
AtomicStampedReference:原子更新引用类型,这种更新方式会带有boolean值,是为了解决 CAS 的引用变量是否被更改的问题;
5. 原子数组
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
demo(
()-> new AtomicIntegerArray(10),
(array) -> array.length(),
(array, index) -> array.getAndIncrement(index),
array -> System.out.println(array)
);
6. 字段更新器
AtomicReferenceFieldUpdater // 域 字段
AtomicIntegerFieldUpdater
AtomicLongFieldUpdater
利用字段更新器,可以针对对象的某个域(Field)进行原子操作,只能配合 volatile 修饰的字段使用,否则会出现异常
public class Test5 {
private volatile int field;
public static void main(String[] args) {
AtomicIntegerFieldUpdater fieldUpdater =
AtomicIntegerFieldUpdater.newUpdater(Test5.class, "field");
Test5 test5 = new Test5();
fieldUpdater.compareAndSet(test5, 0, 10);
// 修改成功 field = 10
System.out.println(test5.field);
// 修改成功 field = 20
fieldUpdater.compareAndSet(test5, 10, 20);
System.out.println(test5.field);
// 修改失败 field = 20
fieldUpdater.compareAndSet(test5, 10, 30);
System.out.println(test5.field);
}
}
7. 原子累加器
比较 AtomicLong 与 LongAdder
for (int i = 0; i < 5; i++) {
demo(() -> new LongAdder(), adder -> adder.increment());
}
for (int i = 0; i < 5; i++) {
demo(() -> new AtomicLong(), adder -> adder.getAndIncrement());
}
LongAdder性能更强,原因很简单,就是在有竞争时,设置多个累加单元,Therad-0 累加 Cell[0],而 Thread-1 累加Cell[1]… 最后将结果汇总。这样它们在累加时操作的不同的 Cell 变量,因此减少了 CAS 重试失败,从而提高性能。