像synchronized
這種獨佔鎖屬於悲觀鎖,它是在假設必定會發生衝突的,那麼加鎖剛好有用,除此以外,還有樂觀鎖,樂觀鎖的含義就是假設沒有發生衝突,那麼我正好能夠進行某項操做,若是要是發生衝突呢,那我就重試直到成功,樂觀鎖最多見的就是CAS
。編程
咱們在讀Concurrent包下的類的源碼時,發現不管是ReenterLock內部的AQS,仍是各類Atomic開頭的原子類,內部都應用到了CAS
,最多見的就是咱們在併發編程時遇到的i++
這種狀況。傳統的方法確定是在方法上加上synchronized
關鍵字:bash
public class Test {
public volatile int i;
public synchronized void add() {
i++;
}
}
複製代碼
可是這種方法在性能上可能會差一點,咱們還可使用AtomicInteger
,就能夠保證i
原子的++
了。併發
public class Test {
public AtomicInteger i;
public void add() {
i.getAndIncrement();
}
}複製代碼
CAS源碼分析源碼分析
獲取偏移量valueOffset,性能
public native long objectFieldOffset(Field var1);經過這個方法能夠知道偏移量從jdk底層源碼中獲取。ui
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}複製代碼
而後再看看增長的方法this
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}複製代碼
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;
}複製代碼
var5
獲取的是什麼,經過調用
unsafe的getIntVolatile(var1, var2)
,這是個native方法,具體實現到JDK源碼裏去看了,其實就是獲取
var1
中,
var2
偏移量處的值。
var1
就是
AtomicInteger
,
var2
就是咱們前面提到的valueOffset,這樣咱們就從內存裏獲取到如今valueOffset處的值了
compareAndSwapInt(var1, var2, var5, var5 + var4)
換成compareAndSwapInt(obj, offset, expect, update)
比較清楚,意思就是若是obj
內的value
和expect
相等,就證實沒有其餘線程改變過這個變量,那麼就更新它爲update
,若是這一步的CAS
沒有成功,那就採用自旋的方式繼續進行CAS
操做spa
private volatile int value;和unsafe.getAndAddInt(this, valueOffset, delta);
能夠看出compareAndSwapInt(obj, offset, expect, update)中的obj爲AtomicInteger類型,
AtomicInteger的value值爲volatile類型,在看
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));這裏是一個do,while循環,若是obj內的value和expect不相等,
var5 = this.getIntVolatile(var1, var2);一直會
執行,即不斷從內存中獲取最新的值,來與obj內的value進行比較直到相等爲止。從這個字段能夠看出複製代碼
CAS的缺點線程