欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談一下Java中的悲觀鎖和樂(lè)觀鎖

 更新時(shí)間:2023年04月20日 10:29:05   作者:索碼理  
這篇文章主要介紹了一下Java中的悲觀鎖和樂(lè)觀鎖,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

悲觀鎖和樂(lè)觀鎖是面試高頻問(wèn)題之一,本文將對(duì)悲觀鎖和樂(lè)觀鎖簡(jiǎn)單的進(jìn)行一個(gè)介紹。

悲觀鎖(Pessimistic Locking)

悲觀鎖在并發(fā)環(huán)境中認(rèn)為數(shù)據(jù)隨時(shí)會(huì)被其他線程修改,因此每次在訪問(wèn)數(shù)據(jù)時(shí)都會(huì)加鎖,直到操作完成后才釋放鎖。悲觀鎖適用于寫(xiě)操作多、競(jìng)爭(zhēng)激烈的場(chǎng)景,比如多個(gè)線程同時(shí)對(duì)同一數(shù)據(jù)進(jìn)行修改或刪除操作的情況。悲觀鎖可以保證數(shù)據(jù)的一致性,避免臟讀、幻讀等問(wèn)題的發(fā)生

悲觀鎖就像一個(gè)大保安,總是認(rèn)為有壞人想要偷走共享資源,于是它把資源護(hù)得緊緊的,不讓任何人接近,同時(shí)還會(huì)排隊(duì)等待資源,想要使用就得先獲取鎖,這樣雖然安全可靠,但是也會(huì)導(dǎo)致效率低下,因?yàn)閯e的線程必須等待鎖的釋放才能繼續(xù)執(zhí)行。

Java中常用的悲觀鎖是synchronized關(guān)鍵字和ReentrantLock類(lèi)。

使用synchronized關(guān)鍵字實(shí)現(xiàn)悲觀鎖的代碼如下:

synchronized (lock) {
    //訪問(wèn)共享資源的代碼塊
}

使用ReentrantLock實(shí)現(xiàn)悲觀鎖的代碼如下:

ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
    //訪問(wèn)共享資源的代碼塊
} finally {
    lock.unlock();
}

悲觀鎖存的問(wèn)題:

  • 效率低:悲觀鎖需要獲取鎖才能進(jìn)行操作,當(dāng)有多個(gè)線程需要訪問(wèn)同一份數(shù)據(jù)時(shí),每個(gè)線程都需要先獲取鎖,然后再進(jìn)行操作,如果鎖競(jìng)爭(zhēng)激烈,就會(huì)導(dǎo)致線程等待鎖的釋放,浪費(fèi)了大量的時(shí)間。
  • 容易引起死鎖:悲觀鎖在獲取鎖的過(guò)程中,如果獲取不到就會(huì)一直等待,如果不同的線程都在等待對(duì)方釋放鎖,就會(huì)導(dǎo)致死鎖的情況出現(xiàn)。
  • 可能會(huì)引起線程阻塞:當(dāng)某個(gè)線程獲取到鎖時(shí),其他線程需要等待,如果等待的時(shí)間過(guò)長(zhǎng),就會(huì)導(dǎo)致線程阻塞,影響應(yīng)用的性能。

樂(lè)觀鎖

樂(lè)觀鎖在并發(fā)環(huán)境中認(rèn)為數(shù)據(jù)一般情況下不會(huì)被其他線程修改,因此在訪問(wèn)數(shù)據(jù)時(shí)不加鎖,而是在更新數(shù)據(jù)時(shí)進(jìn)行檢查。如果檢查到數(shù)據(jù)被其他線程修改,則放棄當(dāng)前操作,重新嘗試更新。

樂(lè)觀鎖適用于讀操作多、寫(xiě)操作少的場(chǎng)景,比如多個(gè)線程同時(shí)對(duì)同一數(shù)據(jù)進(jìn)行讀取操作的情況。樂(lè)觀鎖可以減少鎖的競(jìng)爭(zhēng),提高系統(tǒng)的并發(fā)性能。

樂(lè)觀鎖就像一個(gè)樂(lè)天派,總是認(rèn)為沒(méi)有壞人想要偷走共享資源,于是它就不怎么防范,直接對(duì)資源進(jìn)行操作,如果沒(méi)有其他線程對(duì)資源進(jìn)行修改,操作就會(huì)成功,否則就會(huì)進(jìn)行重試,這樣雖然效率高,但是如果多個(gè)線程同時(shí)進(jìn)行修改,就會(huì)導(dǎo)致競(jìng)爭(zhēng)和沖突,需要進(jìn)行額外的處理。

Java中常用的樂(lè)觀鎖是基于CAS(Compare and Swap,比較和交換)算法實(shí)現(xiàn)的。

CAS操作包括三個(gè)操作數(shù):內(nèi)存地址V、舊的預(yù)期值A(chǔ)新的值B。CAS操作首先讀取內(nèi)存地址V中的值,如果該值等于舊的預(yù)期值A(chǔ),那么將內(nèi)存地址V中的值更新為新的值B;

否則,不進(jìn)行任何操作。在更新過(guò)程中,如果有其他線程同時(shí)對(duì)該共享資源進(jìn)行了修改,那么CAS操作會(huì)失敗,此時(shí)需要重試更新操作。

下面是一段基于CAS算法實(shí)現(xiàn)的樂(lè)觀鎖代碼:

// 假設(shè)共享資源為變量value,初始值為1
AtomicInteger value = new AtomicInteger(1);
// 假設(shè)舊的預(yù)期值為1,新的值為2
int expect = 1;
int update = 2;

// 使用CAS操作更新共享資源的值
while (true) {
    // 讀取共享資源的當(dāng)前值
    int current = value.get();
    // 如果當(dāng)前值等于舊的預(yù)期值,使用CAS操作將新的值更新到共享資源中
    if (current == expect) {
        if (value.compareAndSet(expect, update)) {
            // 更新成功,退出循環(huán)
            break;
        } else {
            // 更新失敗,可能是因?yàn)槠渌€程修改了共享資源的值,重試更新操作
            continue;
        }
    } else {
        // 當(dāng)前值不等于舊的預(yù)期值,說(shuō)明共享資源的值已經(jīng)被其他線程修改,重試更新操作
        continue;
    }
}

在這段代碼中,內(nèi)存地址V對(duì)應(yīng)的是AtomicInteger對(duì)象value,舊的預(yù)期值A(chǔ)對(duì)應(yīng)的是變量expect新的值B對(duì)應(yīng)的是變量update。使用AtomicInteger對(duì)象可以保證CAS操作的原子性,即只有一個(gè)線程能夠成功更新共享資源的值。使用compareAndSet方法可以判斷共享資源的值是否等于舊的預(yù)期值,并嘗試將新的值更新到共享資源中。如果更新成功,就退出循環(huán);否則,說(shuō)明共享資源的值已經(jīng)被其他線程修改,需要重試更新操作。

在實(shí)際應(yīng)用中,樂(lè)觀鎖的實(shí)現(xiàn)通常比這個(gè)簡(jiǎn)單實(shí)現(xiàn)要復(fù)雜。例如,在對(duì)數(shù)據(jù)庫(kù)中的數(shù)據(jù)進(jìn)行更新時(shí),需要在更新操作中同時(shí)更新版本號(hào)和其他字段的值,并且需要處理更新失敗和重試的情況。

樂(lè)觀鎖存在的問(wèn)題

CAS雖然很?效的解決原?操作,但是CAS仍然存在三?問(wèn)題:ABA問(wèn)題自旋時(shí)間過(guò)長(zhǎng)只能保證單個(gè)變量的原子性。

  • ABA問(wèn)題:CAS算法在比較和替換時(shí)只考慮了值是否相等,而沒(méi)有考慮到值的版本信息。如果一個(gè)值在操作過(guò)程中被修改了兩次,從原值變成新值再變回原值,此時(shí)CAS會(huì)認(rèn)為值沒(méi)有發(fā)生變化,從而出現(xiàn)操作的錯(cuò)誤。為了解決ABA問(wèn)題,可以在共享資源中增加版本號(hào),每次修改操作都將版本號(hào)加1,從而保證每次更新操作的唯一性。在更新數(shù)據(jù)時(shí)先讀取當(dāng)前版本號(hào),如果與自己持有的版本號(hào)相同,則可以更新數(shù)據(jù),否則更新失敗。版本號(hào)算法可以避免ABA問(wèn)題,但需要維護(hù)版本號(hào),增加了代碼復(fù)雜度和內(nèi)存開(kāi)銷(xiāo)。
  • 自旋時(shí)間過(guò)長(zhǎng):由于CAS算法在失敗時(shí)會(huì)一直自旋,等待共享變量可用,如果共享變量一直不可用,就會(huì)出現(xiàn)自旋時(shí)間過(guò)長(zhǎng)的問(wèn)題,浪費(fèi)CPU資源。
  • 只能保證單個(gè)變量的原子性:CAS算法只能保證單個(gè)變量的原子性,如果需要多個(gè)變量的原子操作,就需要使用鎖等其他方式進(jìn)行保護(hù)。

悲觀鎖和樂(lè)觀鎖的對(duì)比

悲觀鎖樂(lè)觀鎖
性能
數(shù)據(jù)一致性
實(shí)現(xiàn)復(fù)雜度簡(jiǎn)單復(fù)雜
加鎖方式基于鎖機(jī)制基于版本號(hào)機(jī)制
應(yīng)用場(chǎng)景讀少寫(xiě)多讀多寫(xiě)少
存在的問(wèn)題效率低、容易引起死鎖、可能會(huì)引起線程阻塞ABA問(wèn)題、自旋時(shí)間過(guò)長(zhǎng)、只能保證單個(gè)變量的原子性

總結(jié)

悲觀鎖和樂(lè)觀鎖各有優(yōu)缺點(diǎn),應(yīng)根據(jù)具體的業(yè)務(wù)場(chǎng)景和性能需求來(lái)選擇合適的鎖機(jī)制。在實(shí)際應(yīng)用中,也可以考慮使用兩種鎖機(jī)制的組合,例如在高并發(fā)讀寫(xiě)的情況下,可以使用樂(lè)觀鎖來(lái)提高讀操作的效率,同時(shí)在寫(xiě)操作時(shí)使用悲觀鎖來(lái)保證數(shù)據(jù)的一致性。

到此這篇關(guān)于淺談一下Java中的悲觀鎖和樂(lè)觀鎖的文章就介紹到這了,更多相關(guān)Java悲觀鎖和樂(lè)觀鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Servlet中/和/*的區(qū)別詳解

    Servlet中/和/*的區(qū)別詳解

    本文將分析/和/*的區(qū)別這個(gè)老生常談的問(wèn)題,但是很多時(shí)候看完就忘了,關(guān)于此問(wèn)題這一篇文章就夠了,它將成為你的永久記憶,感興趣的可以了解一下
    2021-07-07
  • Spring MVC學(xué)習(xí)教程之視圖深入解析

    Spring MVC學(xué)習(xí)教程之視圖深入解析

    這篇文章主要給大家介紹了關(guān)于Spring MVC學(xué)習(xí)教程之視圖解析的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或使用spring mvc具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧
    2018-11-11
  • Java使用elasticsearch基礎(chǔ)API使用案例講解

    Java使用elasticsearch基礎(chǔ)API使用案例講解

    這篇文章主要介紹了Java使用elasticsearch基礎(chǔ)API使用案例講解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Spring中Controller應(yīng)用深入理解

    Spring中Controller應(yīng)用深入理解

    這篇文章主要介紹了Spring項(xiàng)目中的Controller,Spring Controller本身也是一個(gè)Spring Bean,只是它多提供了Web能力,只需要造類(lèi)上提供@Controller注解即可
    2022-12-12
  • 如何正確控制springboot中bean的加載順序小結(jié)篇

    如何正確控制springboot中bean的加載順序小結(jié)篇

    這篇文章主要介紹了如何正確控制springboot中bean的加載順序總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Java實(shí)現(xiàn)單線程聊天室

    Java實(shí)現(xiàn)單線程聊天室

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)單線程聊天室,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • 實(shí)例講解Java中random.nextInt()與Math.random()的基礎(chǔ)用法

    實(shí)例講解Java中random.nextInt()與Math.random()的基礎(chǔ)用法

    今天小編就為大家分享一篇關(guān)于實(shí)例講解Java中random.nextInt()與Math.random()的基礎(chǔ)用法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-02-02
  • Java三個(gè)類(lèi)加載器及它們的相互關(guān)系

    Java三個(gè)類(lèi)加載器及它們的相互關(guān)系

    Java在需要使用類(lèi)別的時(shí)候,才會(huì)將類(lèi)別加載,Java的類(lèi)別載入是由類(lèi)別載入器(Class loader)來(lái)達(dá)到的,預(yù)設(shè)上,在程序啟動(dòng)之后,主要會(huì)有三個(gè)類(lèi)別加載器,文中詳細(xì)介紹了這三個(gè)類(lèi)加載器,需要的朋友可以參考下
    2021-06-06
  • Java實(shí)現(xiàn)郵件發(fā)送的過(guò)程及代碼詳解

    Java實(shí)現(xiàn)郵件發(fā)送的過(guò)程及代碼詳解

    這篇文章主要介紹了Java實(shí)現(xiàn)郵件發(fā)送的過(guò)程及代碼詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Java如何實(shí)現(xiàn)單鏈表的增刪改查

    Java如何實(shí)現(xiàn)單鏈表的增刪改查

    這篇文章主要給大家介紹了關(guān)于Java如何實(shí)現(xiàn)單鏈表的增刪改查的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04

最新評(píng)論