簡單探索CAS演算法原理
- 1.CAS演算法理解
- 2.以實體說明CAS演算法的作用
- 總結
看了標題后,許多朋友會不禁發出疑問,什么是CAS演算法? 簡單來說,CAS為Compare and Swap的意思,即比較并交換的演算法,
1.CAS演算法理解
- JDK1.5增加了并法包java.util.concurrent.*,其下面的類使用CAS演算法實作了區別于synchronize同步鎖的一種樂觀鎖,JDK1.5之前Java語言是靠synchronized關鍵字來保證同步的,這是一種獨占鎖(就是有你沒我的意思),也是悲觀鎖,
如一個金融系統,當某個操作員讀取用戶的資料,并在讀出的用戶資料的基礎上進行修改時(如更改用戶帳戶余額),如果采用悲觀鎖機制,也就意味著整個操作程序中(從操作員讀出資料、開始修改直至提交修改結果的全程序),資料庫記錄始終處于加鎖狀態,可以想見,如果面對幾百上千個并發,這樣的情況將導致怎樣的后果,樂觀鎖機制在一定程度上解決了這個問題,
對于CAS的理解,可以簡單將CAS理解為一種無鎖的演算法,CAS中有3個運算元,記憶體值V,預期值A,以及要修改的新值B,當且僅當預期值A與記憶體值V相同時,將記憶體值 V修改為B,否則什么都不做,
2.以實體說明CAS演算法的作用
前面我們了解到了i++的原子性問題:i++演算法在代碼層面只有一步操作,但交給CPU指令進行操作實際上分為3個步驟,即“讀–改--寫”,而前面我們知道volatile可以保證可見性,但是不能保證原子性,
- 實際上除了synchronize實作原子性外,CAS演算法也可以保證資料變數的原子性,
在java.util.concurrent.atmoic包下提供了一些原子變數,所謂原子變數,就是類的小工具包,支持在單個變數上解除鎖的執行緒安全編程,事實上,此包中的類可將voilatile值,欄位和陣列元素概念擴展到那些也提供原子條件更新操作的類,
在原子類變數中,如java.util.concurrent.atomic中的AtomicXXX,都使用了這些底層的JVM支持為數字型別的參考型別提供一種高效的CAS操作,而在java.util.concurrent中的大多數類在實作時都直接或間接的使用了這些原子變數類,
- 與前面的賣票程式一致的代碼,這里采用多執行緒操作多條共享陳述句(i++),代碼如下,所以會發生多執行緒安全問題,這里會出現相同的數字,
public class MyRunnable implements Runnable {
//提供共享變數
static int i=0;
@Override
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//i++不是原子性操作,所以會發生多執行緒安全問題
System.out.println(i++);
}
}
}
public class MyTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
//利用for回圈開啟10個執行緒操縱共享資源,與i++陳述句
for (int i = 0; i < 10; i++) {
new Thread(myRunnable).start();
}
}
}
執行后結果會出現相同的數字:

- 這里除過利用sychronized解決原子性問題,還可以使用CAS演算法來解決,代碼如下:
//在java.util.concurrent.atmoic包下提供了一些原子變數,
// 所謂原子變數,就是類的小工具包,支持在單個變數上解除鎖的執行緒安全編程,
import java.util.concurrent.atomic.AtomicInteger;
public class MyRunnable implements Runnable {
AtomicInteger i= new AtomicInteger(1);
//提供成員變數的get方法
public AtomicInteger getI() {
return i;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i.getAndIncrement());
}
}
}
public class MyTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
for (int i = 0; i < 10; i++) {
new Thread(myRunnable).start();
}
}
}
- 輸出的結果沒有相等的數字,即解決多執行緒安全問題,如下圖,

- AtomicInteger.GetAndincrement 的實作用了樂觀鎖技術,呼叫了類sun.misc.Unsafe庫里面的 CAS演算法,用CPU指令來實作無鎖自增,所以 AtomicInteger.GetAndincrement 的自增比用synchronized的鎖效率倍增,
總結
關于CAS演算法的介紹,到這里就結束了,對于CAS演算法的理解這部分大家要對其處理的思想要弄清楚,面試中談及多執行緒安全問題時也能與面試官聊聊CAS演算法的理解,會很加分呦,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/257052.html
標籤:其他
上一篇:Java-單例模式
