Java多線程 樂觀鎖、悲觀鎖、以及CAS算法

Java多線程 樂觀鎖、悲觀鎖、以及CAS算法

1、樂觀鎖

1.1 概念

該鎖總是很樂觀的,在多線程併發過程中,不會認爲別人每次會修改自己的數據,所以在別人操作時候不會上鎖,如果是讀取數據,那麼直接返回數據,如果是更新數據,那麼做一次判斷,是否有別人更新,等待別人更新後再更新。那麼這個很明顯的優勢就是,性能較高,不會因爲每次上鎖而降低性能,應用於高吞吐的操作。可以使用版本號機制和CAS算法實現

1.2 應用

(1)適用場景
比較適合讀取操作比較頻繁的場景,如果出現大量的寫入操作,數據發生衝突的可能性就會增大,爲了保證數據的一致性,應用層需要不斷的重新獲取數據,這樣會增加大量的查詢操作,降低了系統的吞吐量。

(2)jdk中的應用
在Java中java.util.concurrent.atomic包下面的原子變量類就是使用了樂觀鎖的一種實現方式CAS(compare and set)實現的。
例如:
AtomicBoolean(用原子方式更新的boolean值)

AtomicInteger(用原子方式更新的int值)

AtomicLong(用原子方式更新的long值)

簡單實例

class Count{

    // 共享變量(使用AtomicInteger來替代Synchronized鎖)

    private AtomicInteger count = new AtomicInteger(0);

    public Integer getCount() {

        return count.get();

    }

    public void increase() {

        count.incrementAndGet();

    }

}

1.3 樂觀鎖的缺點

(1)只能保證一個共享變量的原子操作
CAS 只對單個共享變量有效,當操作涉及跨多個共享變量時 CAS 無效。但是從 JDK 1.5開始,提供了AtomicReference類來保證引用對象之間的原子性,你可以把多個變量放在一個對象裏來進行 CAS 操作.所以我們可以使用鎖或者利用AtomicReference類把多個共享變量合併成一個共享變量來操作。

(2)ABA 問題
如果一個變量V初次讀取的時候是A值,並且在準備賦值的時候檢查到它仍然是A值,那我們就能說明它的值沒有被其他線程修改過了嗎?很明顯是不能的,因爲在這段時間它的值可能被改爲其他值,然後又改回A,那CAS操作就會誤認爲它從來沒有被修改過。這個問題被稱爲CAS操作的 "ABA"問題。

JDK 1.5 以後的 AtomicStampedReference 類就提供了此種能力,其中的 compareAndSet 方法就是首先檢查當前引用是否等於預期引用,並且當前標誌是否等於預期標誌,如果全部相等,則以原子方式將該引用和該標誌的值設置爲給定的更新值。

(3)循環時間長開銷大
自旋CAS(也就是不成功就一直循環執行直到成功)如果長時間不成功,會給CPU帶來非常大的執行開銷。

2 、悲觀鎖

2.1 概念

該類鎖總是很悲觀的,在多線程併發過程中,總是認爲別人會侵犯自己,比如別人來讀取或者修改數據,都會先上鎖,當處理完成後再釋放鎖。如果是寫,倒是還好,如果只是讀取呢?那麼勢必會減低讀取性能。這種鎖獨自佔用資源,也叫做獨佔鎖

2.2 應用

(1)適用的應用場景
比較適合寫入操作比較頻繁的場景,如果出現大量的讀取操作,每次讀取的時候都會進行加鎖,這樣會增加大量的鎖的開銷,降低了系統的吞吐量。

(2)jdk中的應用

Java中synchronized和ReentrantLock等獨佔鎖

3、CAS算法

3.1 CAS 算法原理

(1)CAS有3個操作數,內存值V舊的預期值E要修改的新值N。當且僅當預期值E和內存值V相同時,將內存值V修改爲N,否則什麼都不做。但一般情況下是一個自旋操作,即不斷的重試。
(2)過程大概如下圖:
在這裏插入圖片描述

3.2 CAS與synchronized的使用情景

(1)CAS適用於寫比較少的情況下(多讀場景,衝突一般較少)
對於資源競爭較少(線程衝突較輕)的情況,使用synchronized同步鎖進行線程阻塞和喚醒切換以及用戶態內核態間的切換操作額外浪費消耗cpu資源;而CAS基於硬件實現,不需要進入內核,不需要切換線程,操作自旋機率較少,因此可以獲得更高的性能。

(2)synchronized適用於寫比較多的情況下(多寫場景,衝突一般較多)。
對於資源競爭嚴重(線程衝突嚴重)的情況,CAS自旋的概率會比較大,從而浪費更多的CPU資源,效率低於synchronized

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章