Atomic 原子類詳解

Yfeil發表於2024-04-29

1.AtomicIntegerAtomicLongAtomicBooleanAtomicReference:基礎

// atomicInteger:整型原子類
AtomicInteger atomicInteger = new AtomicInteger(0);
atomicInteger.incrementAndGet();// 自增取新值
atomicInteger.decrementAndGet();// 自減取新值
atomicInteger.addAndGet(1);// 增加取新值
atomicInteger.getAndIncrement();// 自增取原值
atomicInteger.getAndDecrement();// 自減取原值
atomicInteger.getAndAdd(1);// 增加取原值
atomicInteger.getAndSet(10);// 設定取原值
atomicInteger.compareAndSet(10, 20);// 比較並設定,返回是否成功

// AtomicLong:長整型原子類,使用方式同上

// AtomicBoolean:布林型原子類
AtomicBoolean atomicBoolean = new AtomicBoolean(false);
atomicBoolean.set(true);// 設定
atomicBoolean.compareAndSet(false, true);// 比較並設定,返回是否成功

// AtomicReference:引用型原子類
AtomicReference<String> atomicReference = new AtomicReference<>("Hello");
atomicReference.set("World");// 設定
atomicReference.compareAndSet("World", "Hello Again");// 比較並設定,返回是否成功

2.AtomicIntegerArrayAtomicLongArrayAtomicReferenceArray:陣列

// AtomicIntegerArray:整型陣列
AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(10);
atomicIntegerArray.set(/*索引*/ 5, 10);// 設定
atomicIntegerArray.addAndGet(/*索引*/ 5, 5);// 增加取新值
atomicIntegerArray.compareAndSet(/*索引*/ 5, 10, 15);// 比較並設定,返回是否成功

// AtomicLongArray:長整型陣列,使用方式同上

// AtomicReferenceArray:引用型陣列
AtomicReferenceArray<String> atomicReferenceArray = new AtomicReferenceArray<>(10);
atomicReferenceArray.set(5, "Hello");// 設定
String newValue = atomicReferenceArray.getAndSet(5, "World");// 設定取原值
boolean success = atomicReferenceArray.compareAndSet(5, "Hello", "Hello Again");// 比較並設定

2.AtomicIntegerFieldUpdaterAtomicLongFieldUpdaterAtomicReferenceFieldUpdater:欄位更新器

private static class MyClass {
    // 欄位要求:
    // 1.volatile修飾
    // 2.非static
    // 3.public 或者有 get 和 set 方法
    volatile int intValue;
}

public static void main(String[] args) {
    MyClass myClass = new MyClass();

    // 建立AtomicIntegerFieldUpdater
    AtomicIntegerFieldUpdater<MyClass> intFieldUpdater =
            AtomicIntegerFieldUpdater.newUpdater(MyClass.class, "intValue");

    intFieldUpdater.set(myClass, 10);// 設定
    int newValue = intFieldUpdater.incrementAndGet(myClass);// 自增取新值

    // 更多方法,參考普通整型原子類...

    // AtomicLongFieldUpdater:長整型使用方式同上

    // AtomicReferenceFieldUpdater:引用型使用方式同上
}

3.AtomicStampedReferenceAtomicMarkableReference:帶標誌引用型,可用於避免ABA問題

// AtomicStampedReference:帶版本號
AtomicStampedReference<String> stampedReference = new AtomicStampedReference<>("Hello", 0);
boolean success = stampedReference.compareAndSet(/*原值*/ "Hello", "World", /*原標誌*/ 0, 1);// 比較並設定,返回是否成功
stampedReference.getReference();// 取引用
stampedReference.getStamp();// 取標誌

// AtomicMarkableReference:帶布林值
AtomicMarkableReference<String> markableReference = new AtomicMarkableReference<>("Hello", false);

// 原子性地更新引用和標記
boolean markSuccess = markableReference.compareAndSet(/*原值*/ "Hello", "World", /*原標誌*/ false, true);// 比較並設定,返回是否成功
markableReference.getReference();// 取引用
markableReference.isMarked();// 取標誌

4.LongAdderDoubleAdderLongAccumulatorDoubleAccumulator:累加器

原理:LongAdder在內部維護一個陣列,當多個執行緒嘗試同時修改時,會分散到不同的陣列中進行更新。在獲取結果時,將所有陣列的值相加得到總和。

優點:減少併發修改時的CAS競爭,高併發場景下效能優於AtomicLong

缺點:如果計算總和期間有執行緒修改,此次修改可能不會計入這次計算,所以不適合需要精確計算的場景。

// LongAdder:長整型累加器
LongAdder adder = new LongAdder();
adder.add(10);// 增加
adder.increment(); // 自增
adder.sum()// 取總和
adder.reset();// 重置為0

// DoubleAdder:小數型累加器,使用方式同上

// LongAccumulator:長整型自定累加器,使用乘法累加
LongAccumulator accumulator = new LongAccumulator((/*當前值*/ x, /*新值*/ y) -> x * y, /*初始值*/ 1L);
accumulator.accumulate(2); // 計算 accumulator = 1 * 2 = 2
accumulator.accumulate(3); // 計算 accumulator = 2 * 3 = 6
accumulator.get()// 取總和
accumulator.reset();// 重置為初始值

// DoubleAccumulator:小數型自定累加器,使用方式同上

相關文章