(轉(zhuǎn)載)Java CAS 和 synchronized 和 Lock

原文鏈接:Java CAS 和 synchronized 和 Lock - CSDN博客

CAS 機制

適用場景:樂觀認為并發(fā)不高,不需要阻塞,可以不上鎖。?

特點:不斷比較更新,直到成功。

缺點:高并發(fā)cpu壓力大;ABA問題。

ABA問題:?

CAS機制生效的前提是,取出內(nèi)存中某時刻的數(shù)據(jù),而在下時刻比較并替換。?

如果在比較之前,數(shù)據(jù)發(fā)生了變化,例如:A->B->A,即A變?yōu)锽然后又變化A,那么這個數(shù)據(jù)還是發(fā)生了變化,但是CAS還是會成功。

Java中CAS機制使用版本號進行對比,避免ABA問題。

synchronized

適用場景:悲觀認為并發(fā)很高,需要阻塞,需要上鎖。

特點:語言層面的優(yōu)化,鎖粗化、偏向鎖、輕量鎖等等;可讀性高。

ReentrantLock 和 Atomic類

以上兩種并發(fā)工具都使用了CAS機制。?

在并發(fā)不高競爭不激烈時候,性能略低于synchronized;相反,并發(fā)高競爭激烈時候,性能高于synchronized。

ReentrantLock相對于synchronized:

ReentrantLock等待可中斷,synchronized不可以。

ReentrantLock需要手動釋放鎖,synchronized不需要。

ReentrantLock可支持公平非公平鎖,synchronized只支持非公平鎖。

ReentrantLock沒有語言層面的優(yōu)化,底層實現(xiàn)機制AQS和CAS,synchronized有優(yōu)化。

ReentrantLock可重入鎖,synchronized不可重入,可能導致死鎖。

ReentrantLock支持讀寫鎖,可以提高高并發(fā)讀操作。

synchronized由操作系統(tǒng)支持,涉及內(nèi)核態(tài)和用戶態(tài)的上下文切換,并發(fā)高時切換開銷非常大。

ReentrantLock(AQS)依賴volatile int變量標示鎖狀態(tài),結(jié)構(gòu)為雙向鏈表的等待隊列,通過(cas+死循環(huán))更改鎖狀態(tài),一旦更新成功,標示競爭到鎖。

AQS釋放鎖:?

通過cas改變狀態(tài)

private void doReleaseShared() {

? ? ? ? /*

? ? ? ? * Ensure that a release propagates, even if there are other

? ? ? ? * in-progress acquires/releases.? This proceeds in the usual

? ? ? ? * way of trying to unparkSuccessor of head if it needs

? ? ? ? * signal. But if it does not, status is set to PROPAGATE to

? ? ? ? * ensure that upon release, propagation continues.

? ? ? ? * Additionally, we must loop in case a new node is added

? ? ? ? * while we are doing this. Also, unlike other uses of? ? ? ? * unparkSuccessor, we need to know if CAS to reset status

? ? ? ? * fails, if so rechecking.

? ? ? ? */

? ? ? ? for (;;) {

? ? ? ? ? ? Node h = head;

? ? ? ? ? ? if (h != null && h != tail) {

? ? ? ? ? ? ? ? int ws = h.waitStatus;

? ? ? ? ? ? ? ? if (ws == Node.SIGNAL) {

? ? ? ? ? ? ? ? ? ? if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))

? ? ? ? ? ? ? ? ? ? ? ? continue;? ? ? ? ? ? // loop to recheck cases

? ? ? ? ? ? ? ? ? ? unparkSuccessor(h);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? else if (ws == 0 &&

? ? ? ? ? ? ? ? ? ? ? ? !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))

? ? ? ? ? ? ? ? ? ? continue;? ? ? ? ? ? ? ? // loop on failed CAS

? ? ? ? ? ? }

? ? ? ? ? ? if (h == head)? ? ? ? ? ? ? ? ? // loop if head changed

? ? ? ? ? ? ? ? break;

? ? ? ? }

? ? }

獲取鎖:?

如果獲取到鎖,設(shè)為頭節(jié)點,否則一直自旋等待,在高并發(fā)時,可以避免大量鎖競爭的上下文切換,降低線程切換開銷。

private void doAcquireInterruptibly(int arg)

? ? ? ? throws InterruptedException {

? ? ? ? final Node node = addWaiter(Node.EXCLUSIVE);

? ? ? ? boolean failed = true;

? ? ? ? try {

? ? ? ? ? ? for (;;) {

? ? ? ? ? ? ? ? final Node p = node.predecessor();

? ? ? ? ? ? ? ? if (p == head && tryAcquire(arg)) {

? ? ? ? ? ? ? ? ? ? setHead(node);

? ? ? ? ? ? ? ? ? ? p.next = null; // help GC? ? ? ? ? ? ? ? ? ? failed = false;

? ? ? ? ? ? ? ? ? ? return;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? if (shouldParkAfterFailedAcquire(p, node) &&

? ? ? ? ? ? ? ? ? ? parkAndCheckInterrupt())

? ? ? ? ? ? ? ? ? ? throw new InterruptedException();

? ? ? ? ? ? }

? ? ? ? } finally {

? ? ? ? ? ? if (failed)

? ? ? ? ? ? ? ? cancelAcquire(node);

? ? ? ? }

? ? }

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容