在java.util.concurrent.atomic包下面,有許多的原子類,這裏面的操做類型大多數與JAVA中基本類型的包裝類對應。目的是爲了防止高併發的狀況下,各個線程操做產生錯誤數據。這裏就經過AtomicInteger這個類進行爲你們簡單講解下。java
經過源碼咱們發現。AtomicInteger中只有三個屬性,一個
unsafe
對象屬性,一個valueOffset
屬性以及一個被volatile修飾的value
屬性。多線程
1.unsafe
屬性能夠看到是由Unsafe類調用其靜態方法生成。併發
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
複製代碼
Unsafe類提供了硬件級別的原子操做。裏面有許多的本地方法。JDK中的一些無鎖併發操做類都是基於它,裏面最主要的就是CAS相關操做。這塊我就不詳細說明了(有興趣的小夥伴能夠去了解下)。app
2.valueOffset
屬性是當前類中值value對應的內存起始地址。經過當前類中的靜態代碼塊能夠看出,他的賦值狀況:函數
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
複製代碼
他是經過unsafe獲取到當前類中的屬性的起始地址。來進行賦值。點擊到下面能夠看到調用的objectFieldOffset
的native方法進行調用獲取。高併發
3.value
屬性就是當前類中的值,這裏也就是咱們所須要的值。這裏能夠從外部傳遞過來。性能
public AtomicInteger(int initialValue) {
value = initialValue;
}
複製代碼
由當前的類型,咱們就能瞭解到這是一個原子類相關操做,即每個操做不須要考慮多線程併發的問題。裏面的方法以下:this
剛開始的構造函數以及get和set方法在這裏就不作說明了。atom
1.lazySet(int)
這個方法字面上說是懶設值,看到對應方法上面的註解說。這個會最終設值(仍是有點懵。。)。因而點擊進去查看對應調用的方法:spa
public native void putOrderedInt(Object var1, long var2, int var4);
複製代碼
看到裏面調用的是unsafe的方法,putOrderedInt
方法是putIntVolatile
方法的延遲實現,不保證值的改變被其餘線程當即看到。同時,unsafe裏面還有對應的putVolatile
方法,改方法能將改動的值當即刷新到內存中。以及存在普通的putInt
方法,該方法不能保證當即刷新到內存中。
2.getAndSet(int newValue)
方法是爲了設置值,裏面就用到了value的內存地址進行設值。
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
複製代碼
3.compareAndSet(int expect, int update)
這個方法就是基於CAS實現的更新數值。 經過無無鎖將多線程設置值的問題解決。若是設置成功返回true,反之沒設置成功。同時這裏也爲其餘操做提供了一個準確的保證。
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
複製代碼
4.weakCompareAndSet(int expect, int update)
方法是針對於當前的數值交換狀況。將這個成員變量更新爲給定的更新後的值(update)若是當前值等於指望值(expect)時。
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
複製代碼
相信一些小夥伴對此方法有點疑惑,由於若是是基於CAS交換的話,不必增長一個weak在方法名上,(同時讓咱們想起來JAVA中的四種引用類型。。),這裏官方就給出瞭解釋:
weakCompareAndSet底層不會建立任何happen-before的保證,也就是不會對volatile字段操做的先後加入內存屏障。由於就沒法保證多線程操做下對除了weakCompareAndSet操做的目標變量( 該目標變量必定是一個volatile變量 )之其餘的變量讀取和寫入數據的正確性。
5.getAndUpdate(IntUnaryOperator updateFunction)
這個方法先很少說,直接上代碼:
public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return prev;
}
複製代碼
這裏面是使用了循環進行更新值,利用的是以前的CAS操做判斷以前的值與以後的值是不是一致的關係。而後進行更新操做。這裏還使用了功能型接口IntUnaryOperator
。
整體來講:AtomicXXX相關的類的操做都是大體相同的,都是使用的是無鎖的CAS操做,對於性能方面可以有所提升,也不須要考慮線程阻塞的狀況發生。對於多線程操做的狀況下仍是很好的一個選擇。