AtomicReference 這個類和AtomicInteger非常類似,只是AtomicReference對應普通的對象引用,而AtomicInteger 它是對整數的封裝,它的方法如下

對weakCompareAndSet 說明:
第一次看weakCompareAndSet doc文檔的說明時,我是困惑的。我並不清楚你說的“fail spuriously”和“not provide ordering guarantees”的確切含義。於是我查詢了些相關資料。
首先,我從jdk 8 的官方文檔的java.util.concurrent.atomic上找到這么二段話:
The atomic classes also support method weakCompareAndSet, which has limited applicability. On some platforms, the weak version may be more efficient than compareAndSet in the normal case, but differs in that any given invocation of the weakCompareAndSet method may return false spuriously (that is, for no apparent reason). A false return means only that the operation may be retried if desired, relying on the guarantee that repeated invocation when the variable holds expectedValue and no other thread is also attempting to set the variable will eventually succeed. (Such spurious failures may for example be due to memory contention effects that are unrelated to whether the expected and current values are equal.) Additionally weakCompareAndSet does not provide ordering guarantees that are usually needed for synchronization control. However, the method may be useful for updating counters and statistics when such updates are unrelated to the other happens-before orderings of a program. When a thread sees an update to an atomic variable caused by a weakCompareAndSet, it does not necessarily see updates to any other variables that occurred before the weakCompareAndSet. This may be acceptable when, for example, updating performance statistics, but rarely otherwise.
一個原子類也支持weakCompareAndSet方法,該方法有適用性的限制。在一些平台上,在正常情況下weak版本比compareAndSet更高效,但是不同的是任何給定的weakCompareAndSet方法的調用都可能會返回一個虛假的失敗( 無任何明顯的原因 )。一個失敗的返回意味着,操作將會重新執行如果需要的話,重復操作依賴的保證是當變量持有expectedValue的值並且沒有其他的線程也嘗試設置這個值將最終操作成功。( 一個虛假的失敗可能是由於內存沖突的影響,而和預期值(expectedValue)和當前的值是否相等無關 )。此外weakCompareAndSet並不會提供排序的保證,即通常需要用於同步控制的排序保證。然而,這個方法可能在修改計數器或者統計,這種修改無關於其他happens-before的程序中非常有用。當一個線程看到一個通過weakCompareAndSet修改的原子變量時,它不被要求看到其他變量的修改,即便該變量的修改在weakCompareAndSet操作之前。
weakCompareAndSet atomically reads and conditionally writes a variable but does not create any happens-before orderings, so provides no guarantees with respect to previous or subsequent reads and writes of any variables other than the target of the weakCompareAndSet.
weakCompareAndSet實現了一個變量原子的讀操作和有條件的原子寫操作,但是它不會創建任何happen-before排序,所以該方法不提供對weakCompareAndSet操作的目標變量以外的變量的在之前或在之后的讀或寫操作的保證。
這二段話是什么意思了,也就是說weakCompareAndSet底層不會創建任何happen-before的保證,也就是不會對volatile字段操作的前后加入內存屏障。因為就無法保證多線程操作下對除了weakCompareAndSet操作的目標變量( 該目標變量一定是一個volatile變量 )之其他的變量讀取和寫入數據的正確性。
AtomicReference 這個類有個問題 就是 如果有2個線程改變了值,最后改回它獲取的值,那么程序也會繼續執行,可能造成重復執行。例如:為賬戶低於多少錢用戶贈送僅僅-張優惠卷,如果他在獲得一張之后,充值了錢又花費了,就會造成多次操作。測試類:
public class AtomicInteget {
public static void main(String[] args) {
AtomicReference<Integer> atomicReference=new AtomicReference<Integer>();
Integer integer = atomicReference.get();
boolean b = atomicReference.compareAndSet(integer, 5);
System.out.println(b);
boolean b1 = atomicReference.compareAndSet(integer, 6);
System.out.println(b1);
boolean b2 = atomicReference.compareAndSet(atomicReference.get(), null);
System.out.println(b2);
System.out.println(atomicReference.get());
boolean b3 = atomicReference.compareAndSet(integer, 6);
System.out.println(b3);
System.out.println(integer);
System.out.println(atomicReference.get());
}
}
結果如下:
true
false
true
null
true
null
6
jdk針對於這種情況,有一個類專門處理這種問題:

AtomicStampedReference<Integer> money = new AtomicStampedReference<Integer>(19, 0);
public static void main(String args[]) {
for (int i = 0; i < 100; i++) {
final int timestap = money.getStamp();
new Thread() {
public void run() {
while (true) {
Integer m = money.getReference();
if (m < 20) {
if (money.compareAndSet(m, m + 20, timestap, timestap + 1)) {
System.out.println("余額小於20元,充值成功,余額:" + money.getReference() + "元");
break;
}
} else {
System.out.println("余額大於20,無需充值");
break;
}
}
}
}.start();
}
new Thread() {
public void run() {
for (int i = 0; i < 100; i++) {
while (true) {
int timestap = money.getStamp();
Integer m = money.getReference();
if (m > 10) {
System.out.println("金額大於10元");
if (money.compareAndSet(m, m - 10, timestap, timestap + 1)) {
System.out.println("成功消費10元,余額:" + money.getReference() + "元");
break;
}
} else {
System.out.println("沒有足夠的金額");
break;
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
