例子
i++的簡單流程
衆所周知,i++分爲三步:html
1. 讀取i的值java
2. 計算i+1安全
3. 將計算出i+1賦給i單元測試
保證i++操做的線程安全
用鎖和volatile
能夠使用鎖來保持操做的原子性和變量可見性,用volatile保持值的可見性和操做順序性;測試
從一個小例子引起的JAVA內存可見性的簡單思考和猜測以及DCL單例模式中的VOLATILE的做用:https://www.cnblogs.com/theRhyme/p/12145461.html;this
用java.util.concurrent.atomic包下的原子類
若是僅僅是計算操做,咱們天然就想到了java.util.concurrent.atomic包下的原子類,則沒必要考慮鎖的升級、獲取、釋放等消耗,也沒必要考慮鎖的粒度、種類、可重入性等;atom
因爲atomic因爲底層是Unsafe對象的CAS操做,缺點也很明顯:須要循環時間開銷,只能是單個變量CAS,ABA問題(經過AtomicStampedReference解決——增長了stamp相似於version標識)。url
AtomicInteger方法源碼
incrementAndGet方法源碼
public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; }
incrementAndGet,先increment,再get,因此獲取的是increment後的值,而unsafe.getAndAddInt先get,因此這裏須要"+1";spa
valueOffset是什麼呢?
private static final long valueOffset; static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } }
AtomicInteger的靜態屬性valueOffset,屬性value的偏移量,在類加載的時候,經過AtomicInteger的Field——"value"初始化,後續經過當前的AtomicInteger實例和該valueOffset obtain該實例value屬性的值;.net
我的對valueOffset的理解
若是想獲取一個對象的屬性的值,咱們通常經過getter方法得到,而sun.misc.Unsafe卻不一樣,咱們能夠把一個對象實例想象成一塊內存,而這塊內存中包含了一些屬性,如何獲取這塊內存中的某個屬性呢?那就須要該屬性在該內存的偏移量了,每一個屬性在該對象內存中valueOffset偏移量不一樣,每一個屬性的偏移量在該類加載或者以前就已經肯定了(則該類的不一樣實例的同一屬性偏移量相等),因此sun.misc.Unsafe能夠經過一個對象實例和該屬性的偏移量用原語得到該對象對應屬性的值;
sun.misc.Unsafe#getAndAddInt IDEA反編譯後的源碼(與JMM相呼應)
public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
unsafe.getAndAddInt具體實現是循環不停的compare主存中取到的值var5(this.getIntVolatile)和當前的線程的工做內存中的值(經過對象實例var1和偏移量var2得到),直到二者equal(保證原子性)則更新爲新值var5+var4(delta) ,從這裏咱們也體會到了Java內存模型(線程不能直接操做主存中的值,須要複製一份到本身的工做內存中)。
getIntVolatile(主存)和compareAndSwapInt都是sun.misc.Unsafe的native方法。
總結
AtomicInteger經過Unsafe對象保證原子性,而Unsafe對象的getAndAddInt方法經過循環比較主存和線程工做內存中的屬性值相等後更新(即CAS)來保證原子性;
AtomicInteger的value屬性也被volatile關鍵字修飾:volatile關鍵字的做用
private volatile int value;
保證i++原子性的幾種方式
下面是一個很是很是簡單的小例子,分別是非線程安全的i++,鎖同步以及Atomic Class:
public class Counter { @Getter private volatile int i = 0; @Getter private volatile AtomicInteger atomicInteger = new AtomicInteger(0); public void increment(){ i++; // 1. 讀取i的值 // 2. 計算i+1 // 3. 把i+1的值賦給i } public void incrementSync(){ synchronized(this) { i++; // 1. 讀取i的值 // 2. 計算i+1 // 3. 把i+1的值賦給i } } public void incrementAtomic(){ // 先increment再返回 atomicInteger.incrementAndGet(); } }
測試類:
public class AtomicityTest { private Counter counter; /** * 每一個線程打印的次數 */ private int count; @Before public void init(){ counter = new Counter(); count = 10000; } /** * 非線程安全的i++ */ @Test public void increment() throws InterruptedException { Thread t1 = new Thread(() -> { for (int i = 0; i < count; i++) { counter.increment(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < count; i++) { counter.increment(); } }); t1.start(); t2.start(); // 單元測試必須新起的線程要在主線程裏join,不然主線程運行完畢,新起的線程還執行完 t1.join(); t2.join(); /* ThreeParamsEquals<Enum, Enum, Enum> equals = (Enum p1, Enum p2, Enum p3) -> p1.equals(p2) && p1.equals(p3); while (true){ if (equals.equals(Thread.State.TERMINATED, t1.getState(), t2.getState())) { break; } }*/ System.out.println(t1.getState()); System.out.println(t2.getState()); // 因爲不是原子性操做,兩個線程執行總共20000次i++,結果i的值都小於20000 System.out.println(counter.getI()); } /** * 線程安全的i++ */ @Test public void incrementSync() throws InterruptedException { Thread t1 = new Thread(() -> { for (int i = 0; i < count; i++) { counter.incrementSync(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < count; i++) { counter.incrementSync(); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(t1.getState()); System.out.println(t2.getState()); // 因爲保證了原子性,順序性,可見性操做,兩個線程執行總共20000次i++,結果i的值都等於20000 System.out.println(counter.getI()); } /** * 原子類AtomicInteger */ @Test public void incrementAtomic() throws InterruptedException { Thread t1 = new Thread(() -> { for (int i = 0; i < count; i++) { counter.incrementAtomic(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < count; i++) { counter.incrementAtomic(); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(t1.getState()); System.out.println(t2.getState()); // 因爲保證了原子性,順序性,可見性操做,兩個線程執行總共20000次i++,結果i的值都等於20000 System.out.println(counter.getAtomicInteger()); } }