高階併發程式設計學習-atomic包學習(重點介紹AtomicInteger、AtomicIntegerFieldUpdater)
Java.util.concurrent兩個子包locks&atomic,官網文件介紹為可以對基本資料、陣列中的基本資料、對類中的基本資料進行操作。
一 atomic包
1. 原子性定義:原子性意味著個時刻,只有一個執行緒能夠執行一段程式碼,這段程式碼通過一個monitor object保護,從而防止多個執行緒在更新共享狀態時相互衝突。經過atomic類修飾的變數具備原子性,不必考慮在多執行緒併發條件下的執行緒安全問題。
(2)對類中的某個成員變數進行修改
使用方法:
//匯入concurrent包下面的AtomicInteger內容 import java.util.concurrent.atomic.AtomicInteger; public class TestAtomic {// 測試concurrent包下的AtomicInteger public static AtomicInteger i = new AtomicInteger(0);// 所有的執行緒操作同一個物件 public static int A = 0; public static void main(String[] args) throws InterruptedException { System.out.println("i累計前"+TestAtomic.i+",A累計前:"+TestAtomic.A); Thread t0= new Thread( new Runnable(){ @Override public void run() { for(int j=0;j<100000;j++) { TestAtomic.A++; TestAtomic.i.getAndIncrement(); } } }); Thread t1= new Thread( new Runnable(){ @Override public void run() { for(int j=0;j<100000;j++) { TestAtomic.A--; TestAtomic.i.decrementAndGet(); } } }); t0.start(); t1.start(); t0.join(); t1.join(); System.out.print("i累計後"+TestAtomic.i+",A累計後:"+TestAtomic.A); } }
上述程式碼的執行結果為:
i累計前0,A累計前:0
i累計後0,A累計後:24531
從上述程式碼中我們可以看出,變數i保證了結果的正確性,原因在於i採用的是AtomicInteger 屬性,變數具備原子性,從而保證了該變數是執行緒安全的。
(2)對已經new出來的某個變數進行修改,保證其原子性。
AtomicIntegerFieldUpdater使用最重要的在於其建構函式,我們可以在其api檔案中檢視
public static <U> AtomicIntegerFieldUpdater<U>newUpdater(Class<U> tclass,
使用方法:
private AtomicIntegerFieldUpdater<Details>
atomicIntegerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater(
Details.class, "numberTimesInvoked" );
詳細使用程式碼:
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; /** * volatiles cannot be used directly in operations that do x = x + 1 for * numbers can be skipped or duplicated when there are multiple threads * involved. * <p> * Hardware supports Atomic Compare And Swap operations. CAS java classes * like AtomicInteger can use this feature of the hardware to ensure that * a "x = x + 1" like operation is atomic. * <p> * However AtomicInteger is significantly more resource intensive than a simple * volatile. If there are many instances of a class which has an AtomicInteger * this increase in resource over a volatile can be significant. * <p> * The AtomicIntegerFieldUpdater comes to the rescue - it can be registered * with a volatile variable of a class and can then be used on multiple * instances of the class. * * If there are 1000s of instances of a class which would ordinarily have * AtomicInteger this can be a big saving. * * AtomicIntegerFieldUpdater is able to update a volatile field of an object * atomically. * * @author John Dickerson */ public class AtomicIntegerFieldUpdaterCounter { // AtomicIntegerFieldUpdater is registered with Details.class so that it // knows it will later be updating the volatile field called // numberTimesInvoked //步驟1 構造方法 private AtomicIntegerFieldUpdater<Details> atomicIntegerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater( Details.class, "numberTimesInvoked" ); /** * Diferent threads can call this method to update the volatile field of * an instance of Details * * @param details Details object which has the volatile field called * "numberTimesInvoked" in it. * * @return the value of the counter after it has been incremented by one */ //步驟2 對AtomicIntegerFieldUpdater修飾的變數進行操作 public int addOne( Details details ){ // performs a "x = x + 1" style atomic operation //return atomicIntegerFieldUpdater.addAndGet( details, 1 ); return this.atomicIntegerFieldUpdater.getAndIncrement(details); } public int subOne(Details details) { return atomicIntegerFieldUpdater.decrementAndGet(details); } /** * See test class for example of using this class with multiple threads, * some of which are writing to the volatile field and some which are * reading from the volatile field * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { final AtomicIntegerFieldUpdaterCounter atomicIntegerFieldUpdaterCounter = new AtomicIntegerFieldUpdaterCounter(); // This call would ordinarily be made by many other threads final Details d=new Details(); System.out.print("物件d的變數numberTimesInvoked累計前:"+d.getNumberTimesInvoked()); System.out.println(",A累計前:"+TestAtomic.A); Thread t0= new Thread( new Runnable(){ @Override public void run() { for(int j=0;j<100000;j++) { atomicIntegerFieldUpdaterCounter.addOne(d); TestAtomic.A++; } } }); Thread t1= new Thread( new Runnable(){ @Override public void run() { for(int j=0;j<100000;j++) { TestAtomic.A++; atomicIntegerFieldUpdaterCounter.subOne(d); } } }); t0.start(); t1.start(); t0.join(); t1.join(); System.out.print("物件d的變數numberTimesInvoked累計後:"+d.getNumberTimesInvoked()); System.out.println(",A累計後:"+TestAtomic.A); } }
/**
* @author John Dickerson
*/
public class Details {
volatile int numberTimesInvoked;
public int getNumberTimesInvoked() {
return numberTimesInvoked;
}
public void setNumberTimesInvoked(int numberTimesInvoked) {
this.numberTimesInvoked = numberTimesInvoked;
}
}
執行結果如下:
物件d的變數numberTimesInvoked累計前:0,A累計前:0
物件d的變數numberTimesInvoked累計後:0,A累計後:199947
從上述程式碼中我們可以看出,新建立的:Details d=newDetails();物件d的變數numberTimesInvoked,經過this.atomicIntegerFieldUpdater.getAndIncrement(d); 構造後成了一個執行緒安全的變數。