天天看點

JAVA多線程之鎖

1.樂觀鎖

    樂觀鎖是一種概念,它認為程式讀多寫少。

    那麼在擷取資料的時候不加鎖,而在更新的時候判斷此期間這個值有沒有改變(讀版本号),如果沒變就加鎖更新,變化了就重新讀取。(CAS)

2.悲觀鎖

    悲觀鎖也是一種概念,它認為程式寫多讀少。

    那麼不管在擷取資料的時候還是更新資料的時候都對操作進行加鎖。

    java中的悲觀鎖常見的就是關鍵詞Synchronized。

    AQS架構下的鎖則是先嘗試cas樂觀鎖去擷取鎖,擷取不到,才會轉換為悲觀鎖,如 RetreenLock

3.自旋鎖

    是一種非阻塞鎖,也就是說,如果某線程需要擷取鎖,但該鎖已經被其他線程占用時,

    該線程不會被挂起,而是在不斷的消耗CPU的時間,不停的試圖擷取鎖,一旦鎖被釋放能立即獲得鎖(減少線程上下文切換,從使用者态到核心态)

    适用于對鎖競争不激烈,且同步代碼執行時間快的程式。

4.同步鎖

    synchronized 它可以把任意一個非 null 的對象當作鎖。

    他屬于獨占式的悲觀鎖,同時屬于可重入鎖。

    Synchronized 核心 元件

        1) Wait Set:哪些調用 wait 方法被阻塞的線程被放置在這裡;

        2) Contention List:競争隊列,所有請求鎖的線程首先被放在這個競争隊列中;

        3) Entry List:Contention List 中那些有資格成為候選資源的線程被移動到 Entry List 中;

        4) OnDeck:任意時刻,最多隻有一個線程正在競争鎖資源,該線程被成為 OnDeck;

        5) Owner:目前已經擷取到所資源的線程被稱為 Owner;

        6) !Owner:目前釋放鎖的線程。

5.ReentrantLock

    ReentantLock 繼承接口 Lock 并實作了接口中定義的方法,他是一種可重入鎖,除了能完

    成 synchronized 所能完成的所有工作外,還提供了諸如可響應中斷鎖、可輪詢鎖請求、定時鎖等避免多線程死鎖的方法。

    PS:ReentantLock和Synchronized相比是鎖可中斷,可加多個鎖,實作公平鎖。

6.Semaphore(信号量)

     Semaphore semaphore = new Semaphore(int permits , boolean isFair)

     在業務代碼使用時表示最多能有permits個線程同時處理,并且能實作是否為公平鎖isFair

7.AtomicXXX(原子操作)

    提供對XXX對象的原子操作

8.可重入鎖(遞歸鎖)

    可重入鎖,也叫做遞歸鎖,指的是同一線程 外層函數獲得鎖之後 ,内層遞歸函數仍然有擷取該鎖的代碼,但不受影響。

    在 JAVA 環境下 ReentrantLock 和 synchronized 都是可重入鎖。

9.公平鎖與非公平鎖

    a.公平鎖:加鎖前檢查是否有排隊等待的線程,優先排隊等待的線程,先來先得(率先請求鎖資源的線程先擷取鎖)

    b.非公平鎖:加鎖時不考慮排隊等待問題,直接嘗試擷取鎖,擷取不到自動到隊尾等待

10.ReadWriteLock(讀寫鎖)

    a.Java并發庫中ReetrantReadWriteLock實作了ReadWriteLock接口并添加了可重入的特性

    b.ReetrantReadWriteLock讀寫鎖的效率明顯高于synchronized關鍵字

    c.ReetrantReadWriteLock讀寫鎖的實作中,讀鎖使用共享模式;寫鎖使用獨占模式,

        換句話說,讀鎖可以在沒有寫鎖的時候被多個線程同時持有,寫鎖是獨占的

    d.ReetrantReadWriteLock讀寫鎖的實作中,需要注意的,當有讀鎖時,寫鎖就不能獲得(鎖更新);

        而當有寫鎖時,除了獲得寫鎖的這個線程可以獲得讀鎖外(鎖降級),其他線程不能獲得讀鎖