成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java鎖的分類:一文列出Java常見的所有鎖,并分析其實(shí)現(xiàn)原理!

開發(fā) 前端
互斥鎖用于控制對(duì)共享資源訪問的一種同步機(jī)制,可以確保在任何給定的時(shí)間點(diǎn)上只有一個(gè)線程可以訪問特定的臨界區(qū)或共享資源。也叫排他鎖。

什么是鎖

鎖是一種同步機(jī)制,用于確保多線程訪問共享資源或執(zhí)行代碼塊時(shí)不發(fā)生沖突

目的:防止數(shù)據(jù)不一致或數(shù)據(jù)損壞的問題

鎖的分類

按鎖的獲取方式分類

  • 內(nèi)置鎖

通過synchronized關(guān)鍵字實(shí)現(xiàn),JVM自動(dòng)管理鎖的獲取與釋放。

  • 每個(gè)對(duì)象關(guān)聯(lián)一個(gè)監(jiān)視器鎖,線程進(jìn)入同步塊時(shí)自動(dòng)獲取。退出時(shí)自動(dòng)釋放。
    特點(diǎn):可重入、非公平、自動(dòng)異常處理
    底層機(jī)制:依賴對(duì)象頭中的Mark Word記錄鎖狀態(tài)
  • 顯式鎖

需要手動(dòng)調(diào)用Lock接口的實(shí)現(xiàn)類(例如:ReentrantLock),提供更靈活的控制

  • 特點(diǎn):支持公平鎖、可中斷、超時(shí)獲取、支持綁定多個(gè)條件變量
    底層機(jī)制:基于AQS(AbstractQueuedSynchronizer)隊(duì)列同步器實(shí)現(xiàn)

按鎖的功能分類

基于多線程能否共享一把鎖,可以把鎖分為共享鎖和互斥鎖

互斥鎖(Mutual Exclusion Lock)


互斥鎖用于控制對(duì)共享資源訪問的一種同步機(jī)制,可以確保在任何給定的時(shí)間點(diǎn)上只有一個(gè)線程可以訪問特定的臨界區(qū)或共享資源。也叫排他鎖

工作原理:互斥鎖有兩種狀態(tài):鎖定和未鎖定。當(dāng)一個(gè)線程想要訪問受保護(hù)的資源時(shí),必須首先嘗試獲取互斥鎖,如果此時(shí)鎖處于未鎖定狀態(tài),則該線程可以所得鎖并繼續(xù)執(zhí)行;如果鎖已經(jīng)被其他線程持有,則當(dāng)前線程會(huì)被阻塞直到鎖釋放。

互斥鎖的特點(diǎn):

  • 原子性:獲取和釋放鎖的過程必須是原子性的,這些操作不能被打斷
  • 唯一性:在同一時(shí)間點(diǎn)上,只有一個(gè)線程可以持有互斥鎖
  • 可重入性:某些實(shí)現(xiàn)允許同一個(gè)線程多次獲取同一把鎖,但是必須保證每次獲取都對(duì)應(yīng)一次釋放
  • 不可剝奪性:一旦一個(gè)線程獲得了互斥鎖,除非該線程主動(dòng)釋放鎖,否則其他線程無法強(qiáng)制剝奪這個(gè)鎖

基于互斥鎖的特點(diǎn),可以避免競(jìng)態(tài)條件和數(shù)據(jù)不一致問題

常見的問題

  • 死鎖:兩個(gè)或多個(gè)線程互相等待對(duì)方持有的資源,從而陷入永久等待狀態(tài)
  • 饑餓:某些線程永遠(yuǎn)得不到執(zhí)行機(jī)會(huì),因?yàn)槠渌€程總是優(yōu)先獲取所需的資源

共享鎖(Shared Lock)

共享鎖也就是讀鎖,是允許多線程共享訪問共享資源的鎖機(jī)制,主要應(yīng)用于讀多寫少的場(chǎng)景。通過區(qū)分讀寫操作,顯著提升并發(fā)性能。

Java中實(shí)現(xiàn)共享鎖的底層原理:【依托于AQS框架】

狀態(tài)管理:AQS使用一個(gè)32位的int變量表示鎖狀態(tài),其中高16位記錄讀鎖的持有數(shù)量,低16位記錄寫鎖的持有數(shù)量。通過CAS操作修改state的值,確保線程安全。

讀鎖和寫鎖共享同一個(gè)CLH同步隊(duì)列,AQS通過CLH完成同步狀態(tài)的管理,若當(dāng)前線程獲取同步狀態(tài)失敗時(shí),AQS則會(huì)將當(dāng)前線程的狀態(tài)信息構(gòu)造成一個(gè)Node節(jié)點(diǎn),添加到CLH隊(duì)列中,并且阻塞當(dāng)前線程;當(dāng)同步狀態(tài)釋放時(shí),會(huì)把首節(jié)點(diǎn)喚醒,使其再次嘗試獲取同步狀態(tài)

什么是CLH同步隊(duì)列?

AQS原理&CLH同步隊(duì)列

讀鎖的特點(diǎn):

  • 共享性:允許多個(gè)線程同時(shí)持有讀鎖
  • 可重入性:同一線程可重復(fù)獲取讀鎖
  • 與寫鎖互斥:如果當(dāng)前線程持有寫鎖,則讀鎖必須等待
public class Cache<K, V> {
    private final Map<K, V> map = new HashMap<>();
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();

    // 讀操作(共享鎖)
    public V get(K key) {
        readLock.lock();
        try {
            return map.get(key);
        } finally {
            readLock.unlock();
        }
    }

    // 寫操作(排他鎖)
    public void put(K key, V value) {
        writeLock.lock();
        try {
            map.put(key, value);
        } finally {
            writeLock.unlock();
        }
    }
}

寫鎖降級(jí)為讀鎖

鎖降級(jí)是指在持有寫鎖的情況下獲取讀鎖,隨后釋放寫鎖的過程

核心邏輯:

  1. 持有寫鎖:確保當(dāng)前線程獨(dú)占資源,其他線程無法讀寫
  2. 獲取讀鎖:在未釋放寫鎖時(shí)獲取讀鎖,防止其他線程獲取寫鎖修改數(shù)據(jù)
  3. 釋放寫鎖:降級(jí)為讀鎖后,允許其他線程讀取數(shù)據(jù),但是不能寫入數(shù)據(jù)
  4. 釋放讀鎖:完成讀操作后釋放讀鎖,允許其他線程獲取寫鎖
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();

writeLock.lock(); // 1. 獲取寫鎖
try {
    // 修改共享數(shù)據(jù)
    readLock.lock(); // 2. 獲取讀鎖
} finally {
    writeLock.unlock(); // 3. 釋放寫鎖(此時(shí)仍持有讀鎖)
}

try {
    // 讀取數(shù)據(jù)(其他線程可并發(fā)讀,但無法寫)
} finally {
    readLock.unlock(); // 4. 釋放讀鎖
}

為什么不支持鎖升級(jí)

鎖升級(jí)是指從讀鎖升級(jí)到寫鎖,Java中并不支持這種操作

可能產(chǎn)生的問題:

  • 死鎖風(fēng)險(xiǎn):如果多個(gè)持有讀鎖的線程同時(shí)嘗試升級(jí)為寫鎖,會(huì)互相等待對(duì)方釋放讀鎖,這樣機(jī)會(huì)造成死鎖。
  • 競(jìng)爭復(fù)雜性:因?yàn)樽x鎖是可重入,并且支持多個(gè)線程同時(shí)持有的,當(dāng)升級(jí)為寫鎖就會(huì)造成長時(shí)間的阻塞,等待釋放所有讀鎖

說完互斥鎖與共享鎖,接下來從線程需不需要鎖住同步資源的角度,又分為悲觀鎖和樂觀鎖

樂觀鎖(Optimistic Lock)

樂觀認(rèn)為并發(fā)沖突概率低,操作時(shí)不加鎖,只在提交時(shí)檢查數(shù)據(jù)是否被修改

實(shí)現(xiàn)方式:CAS算法和StampedLock

AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet(); // 內(nèi)部通過CAS自旋實(shí)現(xiàn)
StampedLock lock = new StampedLock();
long stamp = lock.tryOptimisticRead();
// 讀取共享數(shù)據(jù)...
if (!lock.validate(stamp)) {
    // 數(shù)據(jù)被修改,轉(zhuǎn)為悲觀讀鎖
    stamp = lock.readLock();
    // 重新讀取數(shù)據(jù)...
    lock.unlockRead(stamp);
}

image.pngimage.png

悲觀鎖(Pessimistic Lock)

悲觀認(rèn)為并發(fā)沖突概率高,每次訪問共享資源時(shí),先加鎖再操作

實(shí)現(xiàn)方式:synchronized關(guān)鍵字和Lock實(shí)現(xiàn)類

image.pngimage.png

適用場(chǎng)景:

悲觀鎖適合寫操作多的場(chǎng)景,先加鎖保證寫操作時(shí)數(shù)據(jù)正確

樂觀鎖適合讀操作多的場(chǎng)景,不加鎖的特點(diǎn)能夠大幅度提升性能

根據(jù)等待鎖的方式可分為自旋鎖和阻塞鎖

自旋鎖(Spin Lock)

當(dāng)線程嘗試獲取鎖失敗時(shí),不會(huì)立即放棄CPU,而是通過忙循環(huán)(自旋)不斷嘗試獲取鎖,直到成功為止【默認(rèn)是循環(huán)10次】

實(shí)現(xiàn)自旋鎖的兩種方式

  • 使用原子類的CAS實(shí)現(xiàn)自旋鎖--循環(huán)次數(shù)自行控制
public class SpinLock {
    private AtomicBoolean locked = new AtomicBoolean(false);

    public void lock() {
        while (!locked.compareAndSet(false, true)) {
            // 自旋等待(空循環(huán)或短暫休眠)
        }
    }

    public void unlock() {
        locked.set(false);
    }
}
  • 使用synchronized,--循環(huán)次數(shù)默認(rèn)10次,并可以使用-XX:PreBlockSpin修改該值

如果沒有成功獲得鎖就會(huì)將該線程掛起

自旋鎖存在的問題:

如果線程鎖在線程自旋剛結(jié)束就釋放掉鎖,那么這個(gè)線程切換上下文的代價(jià)是無端的浪費(fèi)--引出了自適應(yīng)自旋鎖

適應(yīng)型自旋鎖:自旋的次數(shù)或時(shí)間不再固定,而是由前一次在同一個(gè)鎖上的自旋時(shí)間及鎖的擁有者的狀態(tài)來決定

  • 如果在同一個(gè)鎖對(duì)象上,自旋等待剛剛成功獲取過鎖,并且持有鎖的線程正在運(yùn)行中,JVM會(huì)認(rèn)為該鎖自旋獲取到鎖的可能性很大,會(huì)自動(dòng)增加等待時(shí)間
  • 如果對(duì)于某個(gè)鎖,自旋很少成功獲取鎖,那就會(huì)減少自旋時(shí)間或直接不自旋了,避免浪費(fèi)處理器資源

這樣的方式來實(shí)現(xiàn)動(dòng)態(tài)預(yù)測(cè)自旋

image.pngimage.png

阻塞鎖(Blocking Lock)

阻塞鎖是指當(dāng)線程獲取不到鎖時(shí),不發(fā)生自旋,直接阻塞。

優(yōu)點(diǎn):避免CPU空轉(zhuǎn),節(jié)省資源

缺點(diǎn):線程切換上下文帶來的額外開銷,響應(yīng)延遲較高

根據(jù)多個(gè)線程獲取同一把鎖時(shí)是否先到先得,分為公平鎖和非公平鎖

公平鎖(Fair Lock)

公平鎖是指線程獲取鎖的順序是按照線程請(qǐng)求鎖的時(shí)間順序來決定的【先到先得】

實(shí)現(xiàn)方式:ReentrantLock(true)

底層機(jī)制:底層維護(hù)了一個(gè)FIFO隊(duì)列,記錄等待鎖的線程;鎖釋放時(shí),優(yōu)先喚醒隊(duì)列中的第一個(gè)線程。

image.pngimage.png

非公平鎖(Non-Fair Lock)

非公平鎖是指線程獲取鎖的順序根據(jù)實(shí)際的競(jìng)爭結(jié)果【誰搶到算誰的】

實(shí)現(xiàn)方式:ReentrantLock(false)或synchronized關(guān)鍵字

底層機(jī)制:新線程嘗試獲取鎖時(shí),直接競(jìng)爭,若競(jìng)爭失敗再進(jìn)入隊(duì)列等待

圖片圖片

公平鎖與非公平鎖的區(qū)別

  • 公平鎖:會(huì)將所有想要獲取鎖的線程放入FIFO,這就必然會(huì)在釋放鎖時(shí),觸發(fā)喚醒線程操作
  • 非公平鎖:會(huì)直接獲取鎖,若獲取成功,則直接占用資源,無需喚醒;而獲取失敗才會(huì)到隊(duì)列排序,當(dāng)釋放鎖時(shí),觸發(fā)喚醒線程操作

所以非公平鎖插隊(duì)失敗就是公平鎖【優(yōu)先使用非公平鎖】

根據(jù)一把鎖能否重復(fù)獲取同一把鎖,分為可重入鎖和非可重入鎖

可重入鎖(Reentrant Lock)

可重入鎖也叫遞歸鎖,是指同一個(gè)線程再外層方法獲取鎖之后,再進(jìn)入該線程的內(nèi)層方法時(shí)會(huì)自動(dòng)獲取鎖

前提條件:鎖對(duì)象得是同一個(gè)對(duì)象或者Class

實(shí)現(xiàn)方式:ReentrantLock和synchronized都是可重入鎖

ReentrantLock lock = new ReentrantLock();
public void recursiveMethod(int n) {
    lock.lock();
    try {
        if (n > 0) {
            recursiveMethod(n - 1); // 遞歸調(diào)用仍可獲取鎖
        }
    } finally {
        lock.unlock();
    }
}
public synchronized void methodA() {
    methodB(); // 同一線程可直接進(jìn)入另一個(gè)同步方法
}
public synchronized void methodB() {}

底層原理:每次獲取鎖時(shí),內(nèi)部維護(hù)一個(gè)計(jì)數(shù)器,只要釋放鎖(unlock)就對(duì)應(yīng)減少計(jì)數(shù)器,反之增加,直到計(jì)數(shù)器歸零后完全釋放鎖

不會(huì)因?yàn)橹矮@取過沒釋放而阻塞

image.pngimage.png

非可重入鎖(Non-Reentrant Lock)

禁止同一線程重復(fù)獲取同一把鎖,若嘗試重復(fù)獲取,線程會(huì)立即阻塞或拋出異常

實(shí)現(xiàn)原理:

  • 鎖狀態(tài)標(biāo)記:僅記錄鎖是否被占用,不跟蹤持有者
  • 重復(fù)獲取行為:若線程已持有鎖,再次調(diào)用lock()會(huì)阻塞或失敗

image.pngimage.png

image.png

根據(jù)在等待鎖的過程中是否可以中斷,分為可中斷鎖與不可中斷鎖

中斷鎖

線程在等待鎖時(shí)可響應(yīng)中斷

java中的中斷鎖:tryLock(time) 和 lockInterruptibly()

ReentrantLock lock = new ReentrantLock();

// 線程A獲取鎖并長期持有(同上)
new Thread(() -> {
    lock.lock();
    try {
        Thread.sleep(10000); // 模擬長時(shí)間持有鎖
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
}).start();
// 線程B嘗試獲取鎖(可中斷)
Thread threadB = new Thread(() -> {
    try {
        lock.lockInterruptibly(); // 可中斷的鎖請(qǐng)求
        try {
            System.out.println("ThreadB獲取鎖成功");
        } finally {
            lock.unlock();
        }
    } catch (InterruptedException e) {
        System.out.println("ThreadB被中斷,退出等待");
    }
});
threadB.start();

// 主線程嘗試中斷線程B
Thread.sleep(1000);
threadB.interrupt(); // 成功中斷線程B

ReentrantLock.lockInterruptibly()底層機(jī)制:通過AQS的acquireInterruptibly()方法實(shí)現(xiàn),內(nèi)部調(diào)用doAcquireInterruptibly()

public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}

// AQS的acquireInterruptibly方法
public final void acquireInterruptibly(int arg) throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (!tryAcquire(arg))
        doAcquireInterruptibly(arg); // 支持中斷的等待
}

不可中斷鎖(Non-Interruptible Lock)

一旦線程開始請(qǐng)求,就會(huì)一直阻塞等待,直到獲取鎖

java中的不可中斷鎖:synchronized和lock()

ReentrantLock lock = new ReentrantLock();

// 線程A獲取鎖并長期持有
new Thread(() -> {
    lock.lock();
    try {
        Thread.sleep(10000); // 模擬長時(shí)間持有鎖
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
}).start();

// 線程B嘗試獲取鎖(不可中斷)
Thread threadB = new Thread(() -> {
    lock.lock(); // 不可中斷的鎖請(qǐng)求
    try {
        System.out.println("ThreadB獲取鎖成功");
    } finally {
        lock.unlock();
    }
});
threadB.start();

// 主線程嘗試中斷線程B
Thread.sleep(1000);
threadB.interrupt(); // 無法中斷線程B的等待

synchronized底層機(jī)制:JVM內(nèi)置鎖機(jī)制,等待鎖的線程進(jìn)入BLOCKED狀態(tài),不響應(yīng)中斷

ReentrantLock.lock()底層機(jī)制:基于AQS框架,使用不可中斷模式加入等待隊(duì)列

使用場(chǎng)景:

  • 不可中斷鎖適用場(chǎng)景

任務(wù)必須完成:如數(shù)據(jù)庫事務(wù)提交、關(guān)鍵數(shù)據(jù)寫入,不允許中途放棄。

簡單同步需求:使用synchronized快速實(shí)現(xiàn)線程安全。

  • 可中斷鎖適用場(chǎng)景
  • 高響應(yīng)性要求:如用戶取消操作、服務(wù)超時(shí)控制。
  • 復(fù)雜任務(wù)管理:線程池任務(wù)調(diào)度、需要優(yōu)雅終止的后臺(tái)服務(wù)。
責(zé)任編輯:武曉燕 來源: 愛編程的杰尼龜
相關(guān)推薦

2015-11-03 09:24:12

Java讀寫鎖分析

2020-10-20 13:50:47

MySQL數(shù)據(jù)庫

2020-01-16 14:59:32

Java鎖優(yōu)化CAS

2020-05-12 15:40:06

MySQ數(shù)據(jù)庫索引

2024-04-02 09:38:21

PythonGIL

2024-01-29 01:08:01

悲觀鎖遞歸鎖讀寫鎖

2024-03-13 08:34:22

2023-11-21 09:41:00

緩存策略存儲(chǔ)

2023-11-29 07:40:12

分布式

2013-06-06 13:10:44

HashMap無鎖

2024-11-28 15:11:28

2023-01-04 13:43:24

讀寫鎖AQS共享模式

2022-05-12 10:53:42

keepalivevrrp協(xié)議

2009-12-08 10:07:29

2025-04-28 02:22:00

2021-02-28 07:49:28

Zookeeper分布式

2011-03-18 10:26:47

Java對(duì)象

2010-04-16 14:55:12

ORACLE鎖

2023-09-08 08:20:46

ThreadLoca多線程工具

2022-08-03 08:01:16

CDN網(wǎng)站服務(wù)器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日韩精品在线观看一区二区 | 看特级黄色片 | 日韩一区av | 99精品在线免费观看 | 国产精品精品3d动漫 | 91福利电影在线观看 | 四虎永久免费影院 | 国产一区二区三区四区在线观看 | 成人午夜激情 | av黄色片在线观看 | 男女羞羞视频在线 | 国产一区欧美一区 | 在线观看国产视频 | 91欧美精品成人综合在线观看 | 久久久久久国产精品免费免费男同 | 亚洲欧美一区二区三区视频 | 九九热精品视频 | 精品一区二区电影 | 久久中文视频 | 乱码av午夜噜噜噜噜动漫 | 亚洲国产aⅴ精品一区二区 免费观看av | 污污免费网站 | 久久精品电影 | 国产黄色精品 | 久草中文在线观看 | 免费a网站 | 国产色爽 | 色偷偷噜噜噜亚洲男人 | 逼逼网| 青青久久 | 国产剧情一区 | av在线视 | 999久久久 | 一区二区蜜桃 | 亚洲第一成人影院 | 最新国产在线 | 91久久久www播放日本观看 | 亚洲国产精品福利 | 国产精品久久久久久久久久久久 | 国产福利在线播放 | 久久激情视频 |