??我們?cè)趯?shí)現(xiàn)一個(gè)計(jì)數(shù)器的時(shí)候,很多情況下為了考慮線程安全郁惜,需要去加鎖,防止計(jì)數(shù)器錯(cuò)亂甲锡,因?yàn)閷?duì)于大多數(shù)count++來(lái)說(shuō)兆蕉,是兩步操作。兩個(gè)步驟的操作缤沦,多線程必然會(huì)產(chǎn)生錯(cuò)亂的現(xiàn)象虎韵。而atomicInteger這些concurrent包中的計(jì)數(shù)器卻不會(huì)。下面我們來(lái)解析下源碼疚俱。以AtomicInteger為例
??首先劝术,看AtomicInteger類,有如下屬性:
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
private volatile int value;
??這里說(shuō)明下呆奕,由此看出這個(gè)類的底層是通過(guò)Unsafe來(lái)實(shí)現(xiàn)的。也就是說(shuō)Unsafe是核心衬吆。有的人會(huì)問(wèn)梁钾,這里為什么可以通過(guò)Unsafe.getUnsafe來(lái)獲取Unsafe的實(shí)例,因?yàn)檫@個(gè)類在rt.jar 包中逊抡。系統(tǒng)的classloader加載姆泻。所以可以獲取到零酪。如果通過(guò)ApplicationClassloader加載,請(qǐng)參見(jiàn)下Unsafe源碼拇勃,明顯是會(huì)拋異常的四苇。
??接下來(lái)看看valueOffset和value的作用:
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
??初始化valueOffset,這里的得到的是內(nèi)存的偏移量方咆。根據(jù)offset可以定位jvm中分配的內(nèi)存地址月腋。這里猜測(cè)就是定一個(gè)變量value,然后初始化把他的內(nèi)存地址放入valueOffset變量里瓣赂。
??這里還有一點(diǎn)比較重要榆骚,我們看下value的定義是volatile。volatile的意義就是copy出來(lái)的副本值始終和主內(nèi)存中的值保持同步煌集。即你永遠(yuǎn)讀取的都是主內(nèi)存中最新的值妓肢。這樣子就保證了讀的一致性。也就是不管多少個(gè)線程苫纤,你讀取的value永遠(yuǎn)是一致的碉钠。
??通過(guò)以上解釋,基本可以概括出來(lái)卷拘,通過(guò)value,valueOffset喊废,unsafe這三個(gè)東西,實(shí)現(xiàn)了AtomicInteger的功能恭金。
??構(gòu)造函數(shù)比較簡(jiǎn)單操禀,無(wú)參和有參。
/**
* Creates a new AtomicInteger with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
/**
* Creates a new AtomicInteger with initial value {@code 0}.
*/
public AtomicInteger() {
}
??這個(gè)相信大家在用AtomicInteger的時(shí)候横腿,用過(guò)了構(gòu)造函數(shù)了颓屑。有參的就是初始化下value的值,從初始化的值開(kāi)始計(jì)數(shù)耿焊。
??下面看下實(shí)際用的比較多的方法揪惦,以getAndIncrement舉例:
/**
* Atomically increments by one the current value.
*
* @return the previous value
*/
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
??這個(gè)就很好理解了,如果看了我之前寫的unsafe的那篇文章就清楚了罗侯,這段代碼的意思就是這個(gè)AtomicInteger對(duì)象的valueOffset內(nèi)存偏移對(duì)應(yīng)的值+1器腋。那么對(duì)于unsafe.getAndAddInt做了些什么。這里要講到CAS的概念了(compareAndSwap)钩杰。我們看下這段內(nèi)在的邏輯:
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;
}
??很顯然纫塌,一個(gè)cas的做法〗才看完這段代碼措左,就知道為什么AtomicInteger效率高了,因?yàn)椴捎昧藰?lè)觀鎖的概念避除。首先獲取了對(duì)象this對(duì)應(yīng)的offset內(nèi)存偏移的值怎披。也就是當(dāng)前值:var5胸嘁。接下來(lái)在while里進(jìn)行判斷,如果該offset內(nèi)存偏移對(duì)應(yīng)的值是var5凉逛,即沒(méi)有被更改過(guò)性宏,那么就更新成var5+var4。這個(gè)就是明顯的樂(lè)觀鎖的概念状飞。如果沒(méi)更新成功毫胜,那么就直接返回啦。
??至此昔瞧,AtomicInteger核心的思想解釋完畢指蚁。大家可以試試自己去實(shí)現(xiàn)個(gè)AtomicInteger的類。