※AtomicInteger
AtomicInteger ai = new AtomicInteger(); // 建構子可給初始值,不給預設為 0 System.out.println(ai.get()); //取得當前值 0 System.out.println(ai.getAndIncrement()); // 後置遞增 0 System.out.println(ai.incrementAndGet()); // 前置遞增 2 System.out.println(ai.getAndAdd(3)); // 2 System.out.println(ai.addAndGet(3)); // 8 System.out.println(ai.getAndSet(7)); // 8 System.out.println(ai.get()); // 7 ai.set(9); // 回傳 void System.out.println(ai.get()); // 9
※increment、decrement 為加減1,想加減更多用 addAndGet、getAndSet
※AtomicXxx Xxx 為 Wrapper 類別,都類似這樣的用法
※AtomicIntegerArray
int[] ints = {1, 2};
AtomicIntegerArray arr = new AtomicIntegerArray(ints);
arr.getAndSet(0, 9); // 第0個改成9
System.out.println(arr.get(0));//成功修改
System.out.println(ints[0]); // 原本的陣列並不會被改
※針對陣列的其中一個索引修改
※AtomicReference
MyClass c1 = new MyClass(1, "Tom");
MyClass c2 = new MyClass(2, "Jerry");
AtomicReference<MyClass> ref = new AtomicReference<>();
ref.set(c1);
ref.compareAndSet(c1, c2);
System.out.println(ref.get().getId());
System.out.println(ref.get().getName());
@Getter
@Setter
class MyClass {
private int id;
private String name;
public MyClass(int id, String name){
this.id = id;
this.name = name;
}
}
※針對整體物件的修改
※AtomicIntegerFieldUpdater
MyClass c1 = new MyClass(1, "Tom");
AtomicIntegerFieldUpdater<MyClass> atomic = AtomicIntegerFieldUpdater.newUpdater(MyClass.class, "id");
System.out.println(atomic.getAndIncrement(c1));
System.out.println(atomic.get(c1));
class MyClass {
volatile int id;
private String name;
MyClass(int id, String name){
this.id = id;
this.name = name;
}
}
※針對物件裡的 Integer 修改,當然替換 Integer 也有其他 Wrapper 類別
※注意 Myclass 的欄位必需不是 private 且為 volatile 才可以,會有錯誤提示
※AtomicReferenceFieldUpdater
MyClass c1 = new MyClass(1, "Tom");
AtomicReferenceFieldUpdater<MyClass, String> atomic = AtomicReferenceFieldUpdater.newUpdater(MyClass.class, String.class, "name");
atomic.set(c1, "Jerry");
// System.out.println(atomic.getAndSet(c1, "Jerry"));
// System.out.println(atomic.compareAndSet(c1, "Tom", "Jerry")); // 舊值如果不是 Tom 就不更新,回傳 boolean
System.out.println(atomic.get(c1));
class MyClass {
private int id;
volatile String name;
MyClass(int id, String name){
this.id = id;
this.name = name;
}
}
※針對物件裡的物件修改
※使用此方式更新的欄位,一定要使用 Wrapper 類別,如此例 id 不是 Integer 會報錯,必需將 MyClass 和 newUpdate 的第二個參數都使用 Integer 才行
※AtomicStampedReference
Integer i1 = 10;
AtomicStampedReference<Integer> atomic = new AtomicStampedReference<>(i1, 200);
System.out.println(atomic.compareAndSet(10, 11, 200, 201)); // true,預期舊值是 10 且 stamp 是 200 就更新值為11,新的 stamp 為201
System.out.println(i1); // 10
System.out.println(atomic.getReference()); // 11
System.out.println(atomic.getStamp()); // 201
System.out.println(atomic.get(new int[]{i1})); // 11
※針對 ABA 的問題,用此類可解決
※前兩個參數 -128~127 因有 cache,看起來不會有問題,但超過就不行了,永遠是false,就算 i1 改用 int 也會自動裝箱成 Integer
Byte、Short、Integer、Long、Character 都有這個問題,可看 XxxCache
後兩個參數沒有這個問題,因為底層是 int
.較好的寫法
AtomicStampedReference<Integer> atomic = new AtomicStampedReference<>(1000, 200); System.out.println(atomic.compareAndSet(atomic.getReference(), 11, 200, 201)); // true,以 atomic 為主就是同個記憶體,這樣就不會有問題了 System.out.println(atomic.getReference()); // 11 System.out.println(atomic.getStamp()); // 201
※這樣子寫就不用管 -128~127 的問題了
.使用 AtomicStampedReference 針對整個物件修改
MyClass c1 = new MyClass(1, "Tom");
MyClass c2 = new MyClass(2, "Jerry");
//Integer i1 = 10;
AtomicStampedReference<MyClass> atomic = new AtomicStampedReference<>(c1, 200);
System.out.println(atomic.compareAndSet(atomic.getReference(), c2, 200, 201)); // true
MyClass ref = atomic.getReference();
System.out.println(ref.getId()); // 2
System.out.println(ref.getName()); // Jerry
System.out.println(atomic.getStamp()); // 201
@Getter
@Setter
class MyClass {
private int id;
private String name;
MyClass(int id, String name) {
this.id = id;
this.name = name;
}
}
※


