【實戰java高并發程序設計 1】Java中的指針:Unsafe類
【實戰Java高并發程序設計 2】無鎖的對象引用:AtomicReference
AtomicReference無法解決上述問題的根本是因為對象在修改過程中,丟失了狀態信息。對象值本身與狀態被畫上了等號。因此,我們只要能夠記錄對象在修改過程中的狀態值,就可以很好的解決對象被反復修改導致線程無法正確判斷對象狀態的問題。
AtomicStampedReference正是這么做的。它內部不僅維護了對象值,還維護了一個時間戳(我這里把它稱為時間戳,實際上它可以使任何一個整數,它使用整數來表示狀態值)。當AtomicStampedReference對應的數值被修改時,除了更新數據本身外,還必須要更新時間戳。當AtomicStampedReference設置對象值時,對象值以及時間戳都必須滿足期望值,寫入才會成功。因此,即使對象值被反復讀寫,寫回原值,只要時間戳發生變化,就能防止不恰當的寫入。
AtomicStampedReference的幾個API在AtomicReference的基礎上新增了有關時間戳的信息:
//比較設置 參數依次為:期望值 寫入新值 期望時間戳 新時間戳public boolean compareAndSet(V expectedReference,V newReference,int expectedStamp,int newStamp)//獲得當前對象引用public V getReference()//獲得當前時間戳public int getStamp()//設置當前對象引用和時間戳public void set(V newReference, int newStamp)
有了AtomicStampedReference這個法寶,我們就再也不用擔心對象被寫壞啦!現在,就讓我們使用AtomicStampedReference在修正那個貴賓卡充值的問題的:
01 public class AtomicStampedReferenceDemo {02 static AtomicStampedReference<Integer> money=new AtomicStampedReference<Integer>(19,0);03 public staticvoid main(String[] args) {04 //模擬多個線程同時更新后臺數據庫,為用戶充值05 for(int i = 0 ; i < 3 ; i++) {06 final int timestamp=money.getStamp();07 newThread() { 08 public void run() { 09 while(true){10 while(true){11 Integerm=money.getReference();12 if(m<20){13 if(money.compareAndSet(m,m+20,timestamp,timestamp+1)){14 System.out.);15 break;16 }17 }else{18 //System.out.println("余額大于20元,無需充值");19 break ;20 }21 }22 }23 } 24 }.start();25 }26 27 //用戶消費線程,模擬消費行為28 new Thread() { 29 publicvoid run() { 30 for(int i=0;i<100;i++){31 while(true){32 int timestamp=money.getStamp();33 Integer m=money.getReference();34 if(m>10){35 System.out.println("大于10元");36 if(money.compareAndSet(m, m-10,timestamp,timestamp+1)){37 System.out.println("成功消費10元,余額:"+money.getReference());38 break;39 }40 }else{41 System.out.println("沒有足夠的金額");42 break;43 }44 }45 try {Thread.sleep(100);} catch (InterruptedException e) {}46 }47 } 48 }.start(); 49 }50 }
第2行,我們使用AtomicStampedReference代替原來的AtomicReference。第6行獲得賬戶的時間戳。后續的贈予操作以這個時間戳為依據。如果贈予成功(13行),則修改時間戳。使得系統不可能發生二次贈予的情況。消費線程也是類似,每次操作,都使得時間戳加1(36行),使之不可能重復。
執行上述代碼,可以得到以下輸出:
余額小于20元,充值成功,余額:39元大于10元成功消費10元,余額:29大于10元成功消費10元,余額:19大于10元成功消費10元,余額:9沒有足夠的金額可以看到,賬戶只被贈予了一次。
【實戰Java高并發程序設計 1】Java中的指針:Unsafe類
【實戰Java高并發程序設計 2】無鎖的對象引用:AtomicReference
摘自:實戰Java高并發程序設計
新聞熱點
疑難解答