第7章 Java的13個原子操作類
原子更新基本數據類型
AtomticBoolean AtomicInteger AtomicLong
AtomicInteger aint = new AtomicInteger(10);
aint.incrementAndGet(); //原子方式將當前值加1,返回自增後的 ++i
aint.decrementAndGet(); //原子方式將當前值減1,返回自減後的 --i
aint.getAndIncrement(); //返回自增前的 i++
aint.getAndDecrement();
aint.addAndGet(5);
aint.addAndGet(-5) ;
aint.compareAndSet(17, 5); //如果輸入的值等於預期值,返回true,並原子的方式設置爲輸入值
aint.get(); //獲取當前值
原子更新數組
AtomicIntegerArray AtomicLongArray AtomicReferenceArray
int[] values = new int[]{1,2,3,4,5};
AtomicIntegerArray ai = new AtomicIntegerArray(values);
System.out.println(ai.addAndGet(0, 2)); //3
System.out.println(ai.getAndIncrement(1)); //2
System.out.println(values[0]); //1
AtomicIntegerArray 的操作和AtomicInteger是類似的,只是多傳遞了一個index。
注意:數組values通過構造方法傳遞進去,AtomicIntegerArray 會根據數組複製一份。所以AtomicIntegerArray內部數組進行修改的時候,不會影響原先的數組。
原子更新引用類型
AtomicReference 原子更新引用類型
AtomicReferenceFieldUpdate:原子更新引用類型裏的字段。
AtomicMarkableReference:原子更新帶有標記位的引用類型。
AtomicReference<User> auser = new AtomicReference<AtomicTest.User>();
User user = new User("mm", "hangzhou", 5);
auser.set(user); //原子方式設置對象
System.out.println("new name: "+auser.get().getName()); //原子方式獲取對象
System.out.println("new age: "+auser.get().getAge());
User useru = new User("dd", "ningbo", 15);
User old = auser.getAndSet(useru); //獲取原有對象,設置新的對象。
System.out.println("old name: "+old.getName());
System.out.println("update name: "+auser.get().getName());
System.out.println("update age: "+auser.get().getAge());
auser.compareAndSet(useru, new User("", "", 0));
如果對useru對象進行改變,auser對應數據也會發生改變。與AtomicIntegerArray不同,AtomicReference與原先的對象是綁定的。同時發生變化。
AtomicReferenceFieldUpdater<User, String> nameUp = AtomicReferenceFieldUpdater.newUpdater(User.class, String.class,"name" );
nameUp.compareAndSet(useru, "dd", "ddd");
System.out.println(useru.getName());
AtomicReferenceFieldUpdater初始化要求傳入三個參數:字段所屬的對象Class,字段Class,字段名。
基於反射。要求字段必須是volatile修飾,並且不能是private
AtomicMarkableReference<User> amuser = new AtomicMarkableReference<AtomicTest.User>(user, false);
amuser.set(useru, true);
System.out.println(amuser.getReference().getName());
AtomicMarkableReference和AtomicReference相比增加了個boolean類型的標記位。
static class User{
public volatile String name;
public volatile String addr;
public volatile int age;
}
爲了避免CAS過程中的ABA問題,併發包提供了兩個類,AtomicStampedReference和AtomicMarkableReference。前者相當於一個[引用,integer]的二元組,後者相當於一個[引用,boolean]的二元組。
AtomicStampedReference可用來作爲帶版本號的原子引用,而AtomicMarkableReference可用於表示如:已刪除的節點。
注:ABA問題是指在CAS操作過程中,假設我們想要把目標值由1改爲2,一般過程是檢測目標值是否爲1,如果爲1就將其設置爲2。但可能在檢測之前目標值變成了3,然後又變成了1,檢測過程並不能察覺到這種變化。這一般不會有什麼影響,但在某些情況下也可能會是一個問題。
原子更新字段類型
AtomicIntegerFieldUpdate:原子更新整形的字段的更新器
AtomicLongFieldUpdate:
AtomicStampedReference: 原子更新帶有版本號的引用類型。