認識非阻塞的同步機制CAS

2021-07-24 02:14:45 字數 2234 閱讀 4500

原文在這裡

在研究執行緒池的執行原理時,看到一段不斷迴圈重試的**,不理解它的原理,看注釋這是cas的實現,所以學會之後記錄下來。

在多執行緒併發下,可以通過加鎖來保證執行緒安全性,但多個執行緒同時請求鎖,很多情況下避免不了要借助作業系統,執行緒掛起和恢復會存在很大的開銷,並存在很長時間的中斷。一些細粒度的操作,例如同步容器,操作往往只有很少**量,如果存在鎖並且執行緒激烈地競爭,排程的代價很大。

總結來說,執行緒持有鎖,會讓其他需要鎖的執行緒阻塞,產生多種風險和開銷。加鎖是一種悲觀方法,執行緒總是設想在自己持有資源的同時,肯定有其他執行緒想要資源,不牢牢鎖住資源還不能放心呢。

在硬體的支援下,出現了非阻塞的同步機制,其中一種常用實現就是cas。

現代的處理器都包含對併發的支援,其中最通用的方法就是比較並交換(compare and swap),簡稱cas。

cas 操作包含三個運算元 —— 記憶體位置(v)、預期原值(a)和新值(b)。如果記憶體位置的值與預期原值相匹配,那麼處理器會自動將該位置值更新為新值。否則,處理器不做任何操作。無論v值是否等於a值,都將返回v的原值。cas 有效地說明了:我認為位置 v 應該包含值 a;如果包含該值,則將 b 放到這個位置;否則,不要更改該位置,只告訴我這個位置現在的值即可。

當多個執行緒嘗試使用cas同時更新乙個變數,最終只有乙個執行緒會成功,其他執行緒都會失敗。但和使用鎖不同,失敗的執行緒不會被阻塞,而是被告之本次更新操作失敗了,可以再試一次。此時,執行緒可以根據實際情況,繼續重試或者跳過操作,大大減少因為阻塞而損失的效能。所以,cas是一種樂觀的操作,它希望每次都能成功地執行更新操作。

public

class simulationcas

public synchronized boolean compareandset(int expectedvalue, int newvalue)

return

false;

}public synchronized int

compareandswap(int expectedvalue, int newvalue)

return oldvalue;

}}

上面的**模擬了cas的操作,其中compareandswap是cas語義的體現,compareandset對value進行了更新操作,並返回成功與否。

幾行**就實現了cas,是不是覺得很簡單呢?但你要知道,cas僅僅告訴你操作結果,操作失敗後一系列重試回退放棄等操作都要自己實現,開發起來遠比使用鎖複雜。

jvm是支援cas的,體現在我們常用的atom原子類,拿atomicinteger分析一下原始碼。

public final int

getandincrement()

}

對atomicinteger進行+1操作,迴圈裡,會將當前值和+1後的目標值傳入compareandset,直到成功才跳出方法。compareandset是不是很熟悉呢,接著來看看它的**。

// setup to use unsafe.compareandswapint for updates

private

static

final unsafe unsafe = unsafe.getunsafe();

public

final

boolean

compareandset(int expect, int update)

compareandset呼叫了unsafe.compareandswapint,這是乙個native方法,原理就是呼叫硬體支援的cas方法。看懂這個應該就能明白atom類的原理,其他方法的實現是類似的。

有了cas的基礎後,可以來研究那段我未看懂的**。

提交乙個執行任務,執行緒池會嘗試增加乙個工作執行緒去處理任務。下面是threadpoolexecutor裡addworker的一段**:

private boolean addworker(runnable firsttask, boolean core) 

}//其他省略

在內迴圈裡,會呼叫compareandincrementworkercount方法增加乙個工作執行緒,原理和atomicinteger的getandincrement方法是一樣的。如果增加成功,直接跳出迴圈,否則在檢查執行緒池狀態後,再次在內迴圈呼叫compareandincrementworkercount,直到新增成功。

現在再看**,瞬間就明白了。

學習非阻塞的同步機制CAS

在研究執行緒池的執行原理時,看到一段不斷迴圈重試的 不理解它的原理,看注釋這是cas的實現,所以學會之後記錄下來。鎖有什麼劣勢 在多執行緒併發下,可以通過加鎖來保證執行緒安全性,但多個執行緒同時請求鎖,很多情況下避免不了要借助作業系統,執行緒掛起和恢復會存在很大的開銷,並存在很長時間的中斷。一些細粒...

非阻塞的同步 無鎖(CAS演算法)

基於鎖的同步方式,是一阻塞的執行緒間同步方式,不同執行緒在鎖競爭時,總不能避免相互等待,為了避免這個問題,就提出了非阻塞同步的方式,最簡單的一種非阻塞同步實現就是threadlocal。另一種方式就是基於比較並交換 compare and swap cas演算法的無鎖併發控制方法。cas演算法的是有...

第十五章 原子變數和非阻塞同步機制

1.非阻塞演算法 如果在演算法中,乙個執行緒的失敗或掛起不會導致其他執行緒也失敗或掛起,那麼這種演算法就稱為非阻塞演算法。如果這種演算法的每個步驟中都存在某個執行緒能夠執行下去,那麼這種演算法也稱為無鎖演算法。這種演算法利用底層的原子機器指令代替鎖來確保資料在併發訪問中的一致性。2.硬體對併發的支援...