天天看點

linux核心無鎖cas,CAS無鎖機制深入了解

1.Java記憶體模型:JMM

在記憶體模型當中定義一個主記憶體,所有聲明的執行個體變量都存在于主記憶體當中,主記憶體的資料會共享給所有線程,每一個線程有一個塊工作記憶體,工作記憶體當中主記憶體資料的副本當更新資料時,會将工作記憶體中的資料同步到主記憶體當中;

linux核心無鎖cas,CAS無鎖機制深入了解

2.什麼是CAS

CAS:Compare and Swap,即比較交換;

jdk1.5增加了并發包java.util.concurrent.*,其下面的類使用CAS算法實作了差別于synchronized同步鎖的一種樂觀鎖。jdk1.5之前java語言是靠synchronized關鍵字保證同步的,這是一種獨占鎖,也是悲觀鎖;

3.CAS算法了解

3.1 與鎖相比,使用比較交換會使程式看起來更加複雜一些。但由于其非阻塞性,它對死鎖問題天生免疫,并且,線程間的互相影響也遠遠比基于鎖的方式要小;更為重要的是,使用無鎖的方式完全沒有鎖競争帶來的系統開銷,也沒有線程間頻繁排程帶來的開銷;是以,它要比基于鎖的方式擁有更優越的性能;

3.2 無鎖的好處:

3.2.1 在高并發情況下,它比有鎖的程式擁有更好的性能;

3.2.2 它天生就是死鎖免疫的;

3.3 CAS算法的過程:

它包含三個參數CAS(V,E,N):V表示更新的變量,E表示預期值,N表示新值;

3.3.1 線程通路時,先會将主記憶體中的資料同步到線程的工作記憶體當中

3.3.2 假設線程A和線程B都有對資料進行更改,那麼假如線程A先擷取到執行權限

3.3.3 線程A先會對比工作記憶體當中的資料和主記憶體當中的資料是否一緻,如果一緻(V==E)則進行更新,不一緻則重新整理資料,重新循環判斷

3.3.4 這時更新完畢後,線程B也要進行資料更新,主記憶體資料和工作記憶體資料做對比,如果一緻則進行更新,不一緻則将主記憶體資料重新更新到工作記憶體,然後循環再次對比兩個記憶體中的資料直到一緻為止

linux核心無鎖cas,CAS無鎖機制深入了解

3.4 CAS操作是抱着樂觀的态度進行的,它總是認為自己可以成功完成操作;當多個線程同時使用CAS操作一個變量時,隻有一個會勝出,并成功更新,其餘均會失敗;失敗的線程不會被挂起,僅是被告知失敗,并且允許再次嘗試,當然也允許失敗的線程放棄操作;基于這樣的原理,CAS操作即使沒有鎖,也可以發現其他線程對目前線程的幹擾,并進行恰當的處理;

3.5 簡單的說,CAS需要你額外給出一個期望值,也就是你認為這個變量現在應該是什麼樣子的;如果變量不是你想象的那樣,那說明它已經被别人修改過了;你就要重新讀取,再次嘗試修改就好了;

3.6 在硬體層面,大部分的現代處理器都已經支援原子性的CAS指令;在jdk1.5以後,虛拟機便可以使用這個指令來實作并發操作和并發資料結構,并且,這種操作在虛拟機中可以說是無處不在;

4.CAS缺點

CAS存在一個很明顯的問題,即ABA問題;

問題:如果變量V初次讀取的時候是A,并且在準備指派的時候檢查到它任然是A,那能說明它的值沒有被其他線程修改過了嗎?

如果在這段時間曾經被改成B,然後有改回A,那CAS操作就會誤任務它從來沒有被修改過。正對這種情況,java并發包提供了一個帶有标記的原子應用類AtomicStampedRefernce,它可以通過變量值的版本來保證CAS的正确性;

5.原子類

java中的原子類大緻可以分為四個類:

原子更新基本類型;

原子更新數組類型;

原子更新引用類型;

原子更新屬性類型;

這些原子類中都是用了無鎖的概念,有的地方直接使用CAS操作的線程安全的類型;

public class AtomicIntegerTest implementsRunnable {private static Integer count=1;private static AtomicInteger atomicInteger=newAtomicInteger();

@Overridepublic voidrun() {while (true){int count=getCountAtomic();

System.out.println(count);if (count>=150){break;

}

}

}public synchronizedInteger getCount(){try{

Thread.sleep(50);

}catch(InterruptedException e) {

e.printStackTrace();

}return count++;

}publicInteger getCountAtomic(){try{

Thread.sleep(50);

}catch(InterruptedException e) {

e.printStackTrace();

}returnatomicInteger.incrementAndGet();

}public static voidmain(String[] args){

AtomicIntegerTest test= newAtomicIntegerTest();

Thread thread1= newThread(test);

Thread thread2= newThread(test);

thread1.start();

thread2.start();

}

}

linux核心無鎖cas,CAS無鎖機制深入了解