AtomicStampedReference AtomicReference解決CAS機制中ABA問題
AtomicStampedReference
AtomicStampedReference它內部不僅維護了對象值,還維護了一個版本號(可以是任何一個整數,它使用整數來表示狀態值)。當AtomicStampedReference對應的數值被修改時,除了更新數據本身外,還必須要更新版本號。因此只要版本號發生變化,就能防止不恰當的寫入。版本號類似於時間戳。
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;
public class Test {
/**
**/
public static void main(String[] args) {
AtomicInteger integer = new AtomicInteger(0);
AtomicStampedReference<Integer> reference = new AtomicStampedReference<>(100,1000);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
integer.compareAndSet(0,1);
integer.compareAndSet(1,0);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean b = integer.compareAndSet(0, 1);
System.out.println("AtomicInteger替換");
if(b) System.out.println("0已經被替換為1");
else System.out.println("替換失敗");
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
reference.compareAndSet(100,-100,
reference.getStamp(), reference.getStamp()+1);
reference.compareAndSet(-100,100,
reference.getStamp(), reference.getStamp()+1);
}
});
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
int stamp = reference.getStamp();
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean b = reference.compareAndSet(100, -100,
stamp, reference.getStamp() + 1);
System.out.println("AtomicStampedReference替換");
if(b) System.out.println("100已經被替換為-100");
else System.out.println("替換失敗");
}
});
t1.start();
t2.start();
t3.start();
t4.start();
}
}
輸出結果:
AtomicInteger替換
0已經被替換為1
AtomicStampedReference替換
替換失敗
AtomicReference
AtomicReference類提供了一個可以原子讀寫的對象引用變量。 原子意味着嘗試更改相同AtomicReference的多個線程(例如,使用比較和交換操作)不會使AtomicReference最終達到不一致的狀態。
import java.util.concurrent.atomic.AtomicReference;
public class ABAObjectTest {
public static void main(String[] args) {
SubObject subObject = new SubObject(100,"一百");
AtomicReference<SubObject> reference = new AtomicReference<>(subObject);
SubObject subObject1 = new SubObject(200,"二百");
SubObject subObject2 = new SubObject(300,"三百");
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
boolean b = reference.compareAndSet(subObject, subObject1);
SubObject object = reference.get();
System.out.println(b);
System.out.println(object);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("=============");
System.out.println(reference.get());
boolean b = reference.compareAndSet(subObject, subObject2);
System.out.println(b);
System.out.println(reference.get());
}
});
t1.start();
t2.start();
}
}
/*輸出結果:
true
SubObject{intNum=200, string='二百'}
=============
SubObject{intNum=200, string='二百'}
false
SubObject{intNum=200, string='二百'}*/
class SubObject {
public int intNum;
public String string;
public int getIntNum() {
return intNum;
}
public void setIntNum(int intNum) {
this.intNum = intNum;
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
public SubObject(int intNum, String string) {
this.intNum = intNum;
this.string = string;
}
public SubObject() {
}
@Override
public String toString() {
return "SubObject{" +
"intNum=" + intNum +
", string='" + string + '\'' +
'}';
}
}