effective java 第66條內(nèi)容說(shuō)到,累計(jì)計(jì)數(shù)i++同步問(wèn)題
一種是用sync修飾符進(jìn)行同步操作
另一種是使用AtomicXXX變量,如AtomicLong 的 getAndIncrement方法
好奇AtomicLong的實(shí)現(xiàn)绩社,原以為也是進(jìn)行同步鎖操作實(shí)現(xiàn)的原子性。
發(fā)現(xiàn)源碼并不是這樣做的纫骑,而是使用了native方法unsafe嫉你,改方法只能在授信的代碼中實(shí)例化如jdk內(nèi)。
代碼如下
public final long getAndIncrement() {
while (true) {
long current = get();
long next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
compareAndSet
public final boolean compareAndSet(long expect, long update) {
return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
}
可以發(fā)現(xiàn)當(dāng)進(jìn)行累加操作時(shí)搅荞,第一時(shí)間沒(méi)有進(jìn)行對(duì)變量的更改操作
而是將累加結(jié)果保存红氯,通過(guò)compareAndSet方法對(duì)變量更改,
使用unsafe CAS方法判斷當(dāng)前值與要累加的值expect對(duì)比咕痛,如果兩個(gè)變量是同一個(gè)痢甘,則進(jìn)行更改操作update->當(dāng)前值,否則返回false CAS存在一個(gè)ABA問(wèn)題茉贡,即當(dāng)判斷值A(chǔ)是否被修改前塞栅,該值被其他線程修改成了B,然后又被修改回了A腔丧,那么CAS仍然認(rèn)為該值是沒(méi)有被修改過(guò)的放椰,進(jìn)行賦值操作
而getAndIncrement原理就是,不斷的loop循環(huán)判斷愉粤,當(dāng)前值有沒(méi)有在累加操作前被其他線程修改了砾医,如果沒(méi)改就賦值,改了就重新累加衣厘,再判斷賦值如蚜。從而形成了類(lèi)似同步的機(jī)制。保證變量的原子性头滔。