atomic原子类实现机制_Java并发包-atomic包-让您彻底掌握AtomicInteger源码
從這一篇文章開始,我開始對并發(fā)包的atomic包進(jìn)行源碼解析,首先通過下面的圖了解以下atomic包中的類都是有哪些?
atomic包中的所有類
這一篇文章首先對AtomicInteger進(jìn)行講解。在上一篇文章中我對并發(fā)包保證共享變量線程安全的機制做了講解,如果對關(guān)鍵字volatile和CAS機制真正了解的話,AtomicInteger的內(nèi)部原理是非常的容易理解的,那就跟著我的思路來打開AtomicInteger的大門吧。
本篇文章的主要內(nèi)容:
1:AtomicInteger的實例2:AtomicInteger的源碼解析1、AtomicInteger的實例
我首先利用一個簡單的例子引入今天的話題:
public class AtomicIntegerTest { private static AtomicInteger ai = new AtomicInteger(0); private static int a = 0; public static void main(String[] args) throws InterruptedException { ordinaryIntegerTest(); atomicIntegerTest(); Thread.sleep(2000); System.out.println("a="+a); System.out.println("ai="+ai.get()); } //普通變量多線程下累加 public static void ordinaryIntegerTest(){ for(int i = 0;i<10;i++){ new Thread(()->{ for(int j = 0;j<10000;j++){ a++; } }).start(); } }//利用AtomicInteger多線程下累加 public static void atomicIntegerTest(){ for(int i = 0;i<10;i++){ new Thread(()->{ for(int j = 0;j<10000;j++){ ai.incrementAndGet(); } }).start(); } }}通過上面的例子,大家能夠猜出答案嗎?運行結(jié)果如下:
通過上面兩個運行結(jié)果可以看出:普通的變量每一次運行結(jié)果都不相同,而AtomicInteger變量每一次運行結(jié)果都是相同的,而且結(jié)果是正確的,所以在多線程下,普通變量無法保證線程安全,而AtomicInteger則在多線程下每一次結(jié)果都是正確的。那么我們知道了在多線程下AtomicInteger是線程安全的,它內(nèi)部怎樣實現(xiàn)的呢?我們接下來進(jìn)入AtomicInteger源碼一探究竟。
2、AtomicInteger的源碼解析
2.1、首先看一下AtomicInteger的定義
public class AtomicInteger extends Number implements java.io.Serializable { //代碼省略}//Number類的定義:主要將當(dāng)前類型轉(zhuǎn)化為基本類型public abstract class Number implements java.io.Serializable { //將當(dāng)前類型轉(zhuǎn)化成int public abstract int intValue(); //將當(dāng)前類型轉(zhuǎn)化為long型 public abstract long longValue(); //將當(dāng)前類型轉(zhuǎn)化為float類型 public abstract float floatValue(); //將當(dāng)前類型轉(zhuǎn)化為double類型 public abstract double doubleValue(); //將當(dāng)前類型轉(zhuǎn)化為byte類型 public byte byteValue() { return (byte)intValue(); } //將當(dāng)前類型轉(zhuǎn)為short類型 public short shortValue() { return (short)intValue(); }}2.2、AtomicInteger的成員變量
上一篇文章我說過,在并發(fā)包中大部分都是利用關(guān)鍵字volatile和CAS機制進(jìn)行保證并發(fā)安全的,所以大家應(yīng)該可以才想到在AtomicInteger成員變量中必定會出現(xiàn)被關(guān)鍵字volatile修飾的變量和原子封裝類Unsafe,接下來開始證明我們的猜想。
//unsafe:表示對原子操作的封裝類private static final Unsafe unsafe = Unsafe.getUnsafe();//被volatile修飾的變量private volatile long value;看到上面的兩個成員變量,大家是不是找到了一點感覺,原來AtomicInteger是通過關(guān)鍵字volatile和CAS保證多線程下安全的修改一個共享變量。接下來我們繼續(xù)往下分析。
//值value在內(nèi)存的偏移地址private static final long valueOffset;//靜態(tài)代碼塊就是獲取這個偏移地址的。static { try { valueOffset = unsafe.objectFieldOffset (AtomicLong.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); }}上面的valueOffset就是變量value在內(nèi)存的地址偏移量,也就是上一篇我介紹的CAS(V,E,N)中的V。
在AtomicInteger中還有一個成員變量,如下:
//表示當(dāng)前虛擬機是否支持long類型無鎖化CAS機制static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();private static native boolean VMSupportsCS8();上面把AtomicInteger的成員變量都介紹完了,通過被volatile修飾的value和unsafe封裝的原子操作通過無鎖化來保證對一個變量的線程安全,我們并沒有看到加鎖,說明AtomicInteger是一種樂觀鎖。
2.3、AtomicInteger的構(gòu)造函數(shù)
//第一個構(gòu)造函數(shù):無參數(shù)構(gòu)造public AtomicLong() {}//第二個構(gòu)造函數(shù):傳遞一個初始化value值。public AtomicLong(long initialValue) { value = initialValue;}構(gòu)造函數(shù)非常的簡單,我們接下來繼續(xù)分析它的一些重要的方法。
2.4、AtomicInteger的重要方法
AtomicInteger類中主要分為四類方法,分別如下:
第一類:對單一value的操作。第二類:對value的復(fù)合操作第三類:對value更加復(fù)雜的操作。第四類:對Number方法的實現(xiàn)。第一類:對value的簡單操作
//對volatile變量value的寫public final void set(long newValue) { value = newValue;}//對volatile變量value的讀public final long get() { return value;}上面兩個方法是對voaltile變量的寫和讀,大家還記得volatile的兩個特性嗎?
1:任意對volatile變量的寫,JMM都會立刻將工作內(nèi)存中的值刷新到主存中。2:任意對volatile變量的讀,JMM都會從主存中復(fù)制一份到自己的工作內(nèi)存。上面的兩個方法是對被volatile修飾的單一變量的寫和讀,并沒有任何的復(fù)合操作,所以它具有可見性、有序性和原子性,所以在多線程下是安全的。
第二類:對value的符合操作
上一篇文章我講過關(guān)鍵字volatile只能保證可見性和有序性(禁止指令重排序),但是volatile不具備原子性的特點,所以對value的復(fù)合操作不能保證線程安全,所以需要在配合CAS原子操作才能保證多線程下對value修改的安全。
//這個方法就是我們所說的CASpublic final boolean compareAndSet(long expect, long update) { return unsafe.compareAndSwapLong(this, valueOffset, expect, update);}//通過CAS原子的設(shè)置value=newValue,然后返回舊值public final int getAndSet(int newValue) { return unsafe.getAndSetInt(this, valueOffset, newValue);}//通過CAS原子的設(shè)置value+1,然后返回+1前的舊值public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1);}//通過CAS原子的設(shè)置value+delta,然后返回+delta前的舊值public final int getAndAdd(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta);}//通過CAS原子的設(shè)置value+1,然后返回+1后的新值public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1;}//通過CAS原子的設(shè)置value+delta,然后返回+delta后的新值public final int addAndGet(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta) + delta;}//通過CAS原子的設(shè)置value-1,然后返回-1前的舊值public final int getAndDecrement() { return unsafe.getAndAddInt(this, valueOffset, -1);}//通過CAS原子的設(shè)置value-1,然后返回-1后的新值public final int decrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, -1) - 1;}上面的方法無非就是通過CAS操作+1或者-1,+delta或者-delta,要么返回舊值,要么返回新值,所以都是一些復(fù)合操作,上面的方法都是調(diào)用了Unsafe中的getAndInt()方法,那么我們繼續(xù)跟進(jìn)到Unsafe中看看這個方法。
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;}上面這個方法是不是非常的熟悉,通過CAS操作,成功則返回,失敗則繼續(xù)自旋。流程圖如下:
上面的幾個方法是對value的復(fù)合操作,不像第一類操作,能夠直接通過關(guān)鍵字volatile就可以保證線程安全,而由于volatile不具備原子性,所以對value的符合操作需要通過volatile+CAS保證線程安全。
1:對value的單一操作:直接通過volatile保證線程安全。2:對value的復(fù)合操作:通過volatile+CAS保證線程安全。第三類操作:通過傳遞功能接口實現(xiàn)對value更復(fù)雜的操作
那什么是對value更復(fù)雜的操作呢?第二類復(fù)合操作只是在原來value的基礎(chǔ)上加上一個值或者減去一個值,那么我們向在value的基礎(chǔ)上乘上一個值或者除以一個值,或者更加復(fù)雜的運算,上面的方法就無法使用了,那么為了解決這個問題就出現(xiàn)了對value更加復(fù)雜的操作,例如:3*value+3這種操作,AtomicInteger就為我們提供了這些方法,通過傳遞一個功能接口,來實現(xiàn)我們想要的,而這個功能接口有一個方法需要我們實現(xiàn),而復(fù)雜的運算就在這個方法中。首先我們看一下這個功能接口:
@FunctionalInterfacepublic interface IntUnaryOperator { /** * Applies this operator to the given operand. * * @param operand the operand * @return the operator result */ int applyAsInt(int operand);}------------------------------@FunctionalInterfacepublic interface IntBinaryOperator { /** * Applies this operator to the given operands. * * @param left the first operand * @param right the second operand * @return the operator result */ int applyAsInt(int left, int right);}功能接口一般會有FunctionalInterface注解,說明是一個功能接口,我們通過applyAsInt()方法實現(xiàn)我們的邏輯。那繼續(xù)看AtomicInteger里面的方法:
//向功能接口方法傳遞value,并通過CAS+自旋原子操作,然后返回舊值public final int getAndUpdate(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return prev;}//向功能接口方法傳遞value,并通過CAS+自旋原子操作,然后返回新值public final int updateAndGet(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return next;}//向功能接口方法傳遞value和指定的x,并通過CAS+自旋原子操作,然后返回舊值public final int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction) { int prev, next; do { prev = get(); next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return prev;}//向功能接口方法傳遞value和指定的x,并通過CAS+自旋原子操作,然后返回新值public final int accumulateAndGet(int x, IntBinaryOperator accumulatorFunction) { int prev, next; do { prev = get(); next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return next;}有的同學(xué)還是不理解這個功能接口,我對這一類舉一個例子:
public class AtomicIntegerTest1 { private static AtomicInteger ai = new AtomicInteger(1); public static void main(String[] args) { //將原來值擴大到原來的2倍 ai.getAndUpdate(new IntUnaryOperator() { @Override public int applyAsInt(int operand) { return operand * 2; } }); System.out.println("ai擴大為原來的2倍:" + ai.get()); //將原來的值擴大原來3倍,在減去指定的x //left:就是value //right:就是我們指定的10 ai.accumulateAndGet(10, new IntBinaryOperator() { @Override public int applyAsInt(int left, int right) { return 3 * left - right; } }); System.out.println("ai擴大為原來的3倍,在減去指定的值:" + ai.get()); }}運行結(jié)果如下:
通過上面的運行結(jié)果,大家是不是理解了這一類方法的作用。
第四類操作:對Number方法的實現(xiàn)
public int intValue() { return get();}public long longValue() { return (long)get();}public float floatValue() { return (float)get();}public double doubleValue() { return (double)get();}這一類方法非常的簡單了,都是調(diào)用get()獲取value,然后轉(zhuǎn)化成不同的基本類型。
上面就是AtomicInteger的全面內(nèi)容了,通過上面的講解,大家是否對AtomicInteger有了一個更加清晰的理解呢?如有什么不明白的地方,歡迎留言交流。如果對你有所幫助,請持續(xù)關(guān)注。
總結(jié)
以上是生活随笔為你收集整理的atomic原子类实现机制_Java并发包-atomic包-让您彻底掌握AtomicInteger源码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 雅马哈机器人左手右手系统_消防管件组装成
- 下一篇: 怎么看到方法内引用方法的注释_网页内文字