Java鎖機制詳解

  • 樂觀鎖/悲觀鎖

  • 公平鎖/非公平鎖

  • 獨享鎖/共享鎖

  • 互斥鎖/讀寫鎖

  • 可重入鎖(又名遞歸鎖)

  • 自旋鎖

  • 分段鎖

  • 偏向鎖/輕量級鎖/重量級鎖

樂觀鎖/悲觀鎖

樂觀鎖與悲觀鎖不是指兩種特定類型的鎖, 而是人們針對并發(fā)同步的角度定義出來的兩種概念
樂觀鎖: 顧名思義, 樂觀, 認為拿到的數(shù)據(jù)沒有被別的線程修改, 不上鎖, 使用版本號來標記當前拿到的數(shù)據(jù), 需要跟新數(shù)據(jù)時, 再去比較當前版本號與期望版本號是否一致, 常用的樂觀鎖有數(shù)據(jù)庫的version, jdk1.8并發(fā)包中的atomin下的原子操作類, 的CAS實現(xiàn)
悲觀鎖:顧名思義, 悲觀, 認為拿到的數(shù)據(jù)會被別的線程修改, 所以拿數(shù)據(jù)的時候先上鎖, 然后進行操作, 操作完成釋放鎖, 常用的悲觀鎖數(shù)據(jù)庫中for update, java synchronezed關鍵字, ReetrantLock 加鎖

公平鎖/非公平鎖

公平鎖是指多個線程按照申請的順序來獲取鎖, 非公平鎖不按照申請的順序來獲取鎖
synchronezed關鍵字, ReetrantLock 默認構造器創(chuàng)建的對象都是非公平鎖
ReetrantLock(true) 創(chuàng)建的是公平鎖

獨享鎖/共享鎖

獨享鎖是指該鎖一次只能被一個線程所持有, 共享鎖是指一個該鎖可以被過個線程所持有
synchronezed關鍵字, ReetrantLock 都是獨享鎖
ReadWriteLick其讀是共享鎖, 寫是獨有鎖

互斥鎖/讀寫鎖

獨享鎖/共享鎖是一致廣義的說法, 互斥鎖/讀寫鎖就是具體的實現(xiàn)
synchronezed關鍵字, ReetrantLock 都是獨享鎖
ReadWriteLock其讀是共享鎖, 寫是獨有鎖

可重入鎖(又名遞歸鎖)

線程可以進入任何一個它已經(jīng)擁有的鎖所同步的代碼塊中, 簡單來說就是線程在外層方法獲取鎖, 進入內層方法會自動獲取鎖, synchronezed關鍵字, ReetrantLock都是可重入鎖, 好處是避免死鎖.

自旋鎖

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

分段鎖

分段鎖是一種鎖的設計, 并不是一種具體的鎖, 最有名的分段鎖設計是ConcurrentHashMap, 將map容器分段出多個Entry數(shù)組, 在push炒作時先確認哪個數(shù)據(jù), 然后再進行加鎖操作.

synchronized與Lock的區(qū)別

  1. synchronized 是屬于JVM層面的關鍵字, Lock是api層面的鎖
  2. synchronized無需手動去釋放鎖, Lock需要手動釋放鎖(可能導致死鎖)
  3. synchronized不可中斷, ReentrantLock可中斷
  4. synchronized非公平鎖, ReentrantLock可以設置為公平非公平鎖
  5. synchronized無法綁定多個Condition, 無法實現(xiàn)分組喚醒, ReentrantLock可以實現(xiàn)

死鎖分析

死鎖的原因

線程A持有鎖A, 嘗試獲取線程B, 線程B持有鎖A嘗試獲取線程B.

代碼分析

public class Resource implements Runnable { 
    private String lockA = null; 
    private String lockB = null; 
    public Resource(String lockA, String lockB) {
        this.lockA = lockA;     
        this.lockB = lockB;  
    } 
    public void run() {    
            synchronized (lockA) {           
                 System.out.println("===" + lockA + "===");     
                 try { 
                         TimeUnit.SECONDS.sleep(1); 
                   } catch (InterruptedException e){ 
                         e.printStackTrace();
                 }  
                 synchronized (lockB){ 
                System.out.println("===" + lockB + "====");  
            }
        }
    }
}


public class LockTest { 
        public static void main(String[] args) {  
                String lockA = "lockA";
                String lockB = "lockB";    
                new Thread(new Resource(lockA, lockB), "A").start(); 
                new Thread(new Resource(lockB, lockA), "B").start();
        }
  }

執(zhí)行效果: 程序一直沒有停止

執(zhí)行效果.png

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容