給大夥來梳理下Java中的各種鎖的分類

  大夥在面試的時候應該會經常碰到線程 併發方面的問題,而且也會問到你各種分佈式鎖的概念,本文就給大家整理了下各種鎖的分類,希望對你有所幫助。

鎖的分類

  我們先總體的來看看有哪些具體的分類

序號 分類
1 樂觀鎖/悲觀鎖
2 獨享鎖/共享鎖
3 互斥鎖/讀寫鎖
4 可重入鎖
5 公平鎖/非公平鎖
6 分段鎖
7 偏向鎖/輕量級鎖/重量級鎖
8 自旋鎖

在這裏插入圖片描述

一、樂觀鎖/悲觀鎖

  注意,樂觀鎖悲觀鎖並不是具體的兩種鎖的實現,而一種設計思想。

樂觀鎖

  顧名思義,就是很樂觀,每次去拿數據的時候都認爲別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。
  樂觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,不加鎖會帶來大量的性能提升,在Java中java.util.concurrent.atomic包下面的原子變量類就是使用了樂觀鎖的一種實現方式CAS(Compare and Swap 比較並交換)實現的。

實現方式

數據版本機制

  實現數據版本一般有兩方式,

  1. 第一種是使用版本號
  2. 第二種是使用時間戳。

以版本號方式爲例。

  版本號方式:一般是在數據表中加上一個數據版本號version字段,表示數據被修改的次數,當數據被修改時,version值會加一。當線程A要更新數據值時,在讀取數據的同時也會讀取version值,在提交更新時,若剛纔讀取到的version值爲當前數據庫中的version值相等時才更新,否則重試更新操作,直到更新成功。

update table set xxx=#{xxx}, version=version+1 where id=#{id} and version=#{version};
CAS操作

  CAS(Compare and Swap 比較並交換),當多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程並不會被掛起,而是被告知這次競爭中失敗,並可以再次嘗試。
  CAS操作中包含三個操作數——需要讀寫的內存位置(V)、進行比較的預期原值(A)和擬寫入的新值(B)。如果內存位置V的值與預期原值A相匹配,那麼處理器會自動將該位置值更新爲新值B,否則處理器不做任何操作。

悲觀鎖

  總是假設最壞的情況,每次去拿數據的時候都認爲別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻塞直到它拿到鎖。比如Java裏面的同步原語synchronized關鍵字的實現就是悲觀鎖。
  悲觀鎖適合操作非常多的場景,保證數據的安全。

二、獨享鎖/共享鎖

  獨享鎖是指該鎖一次只能被一個線程所持有。
  共享鎖是指該鎖可被多個線程所持有。

ReentrantLock

  ReentrantLock是獨享鎖。但是對於Lock的另一個實現類ReadWriteLock,其讀鎖是共享鎖,其寫鎖是獨享鎖。

ReadWriteLock

  ReadWriteLock,其讀鎖是共享鎖,其寫鎖是獨享鎖。讀鎖的共享鎖可保證併發讀是非常高效的,讀寫,寫讀,寫寫的過程是互斥的。

Synchronized

  Synchronized是獨享鎖
  獨享鎖與共享鎖也是通過AQS來實現的,通過實現不同的方法,來實現獨享或者共享。

三、互斥鎖/讀寫鎖

  上面講的獨享鎖/共享鎖就是一種廣義的說法,互斥鎖/讀寫鎖就是具體的實現。
  互斥鎖在Java中的具體實現就是ReentrantLock。
  讀寫鎖在Java中的具體實現就是ReadWriteLock。

四、可重入鎖

  可重入鎖又名遞歸鎖,是指在同一個線程在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖。說的有點抽象,下面會有一個代碼的示例。

ReetrantLock

  ReetrantLock從名字就可以看出是一個重入鎖,其名字是Re entrant Lock 重新進入鎖。

Synchronized

  對於Synchronized而言,也是一個可重入鎖。可重入鎖的一個好處是可一定程度避免死鎖。

public class AtomicDemo {
    // 共享操作的資源 volatile 原子性問題  synchroized Lock AutomicInteger
    private static int count = 0 ;

    private static Lock lock = new ReentrantLock();

    // 定義操作的方法  重入鎖
    private static void incr(){
        try {
            lock.lock();// 枷鎖
            Thread.sleep(1);
            count++;
            decr();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    private static void decr(){
        try {
            lock.lock();// 枷鎖
            Thread.sleep(1);
            count--;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i <100 ; i++) {
            new Thread(new Runnable() {
                public void run() {
                    AtomicDemo.incr();
                }
            }).start();
        }

        Thread.sleep(5000);
        System.out.println("Result:" + count);
    }
}

五、公平鎖/非公平鎖

  公平鎖是指多個線程按照申請鎖的順序來獲取鎖。
  非公平鎖是指多個線程獲取鎖的順序並不是按照申請鎖的順序,有可能後申請的線程比先申請的線程優先獲取鎖。有可能,會造成優先級反轉或者飢餓現象。

ReetrantLock

  ReetrantLock可以通過構造函數指定該鎖是否是公平鎖,默認是非公平鎖。非公平鎖的優點在於吞吐量比公平鎖大。

Synchronized

  對於Synchronized而言,也是一種非公平鎖。由於其並不像ReentrantLock是通過AQS的來實現線程調度,所以並沒有任何辦法使其變成公平鎖。

六、分段鎖

  分段鎖其實是一種鎖的設計,並不是具體的一種鎖,對於ConcurrentHashMap而言,其併發的實現就是通過分段鎖的形式來實現高效的併發操作。
  我們以ConcurrentHashMap來說一下分段鎖的含義以及設計思想,ConcurrentHashMap中的分段鎖稱爲Segment,它即類似於HashMap(JDK7和JDK8中HashMap的實現)的結構,即內部擁有一個Entry數組,數組中的每個元素又是一個鏈表;同時又是一個ReentrantLock(Segment繼承了ReentrantLock)。
  當需要put元素的時候,並不是對整個hashmap進行加鎖,而是先通過hashcode來知道他要放在哪一個分段中,然後對這個分段進行加鎖,所以當多線程put的時候,只要不是放在一個分段中,就實現了真正的並行的插入。
  但是,在統計size的時候,可就是獲取hashmap全局信息的時候,就需要獲取所有的分段鎖才能統計。
  分段鎖的設計目的是細化鎖的粒度,當操作不需要更新整個數組的時候,就僅僅針對數組中的一項進行加鎖操作

七、偏向鎖/輕量級鎖/重量級鎖

  這三種鎖是指鎖的狀態,並且是針對Synchronized。在Java 5通過引入鎖升級的機制來實現高效Synchronized。這三種鎖的狀態是通過對象監視器在對象頭中的字段來表明的。
  偏向鎖是指一段同步代碼一直被一個線程所訪問,那麼該線程會自動獲取鎖。降低獲取鎖的代價。
  輕量級鎖是指當鎖是偏向鎖的時候,被另一個線程所訪問,偏向鎖就會升級爲輕量級鎖,其他線程會通過自旋的形式嘗試獲取鎖,不會阻塞,提高性能。
  重量級鎖是指當鎖爲輕量級鎖的時候,另一個線程雖然是自旋,但自旋不會一直持續下去,當自旋一定次數的時候,還沒有獲取到鎖,就會進入阻塞,該鎖膨脹爲重量級鎖。重量級鎖會讓他申請的線程進入阻塞,性能降低。

八、自旋鎖

  在Java中,自旋鎖是指嘗試獲取鎖的線程不會立即阻塞,而是採用循環的方式去嘗試獲取鎖,這樣的好處是減少線程上下文切換的消耗,缺點是循環會消耗CPU。

好了~鎖的分類就給大夥介紹到這裏,有問題的歡迎大家留言交流!!!

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