最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談一下Java中的悲觀鎖和樂觀鎖

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

悲觀鎖和樂觀鎖是面試高頻問題之一,本文將對悲觀鎖和樂觀鎖簡單的進行一個介紹。

悲觀鎖(Pessimistic Locking)

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

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

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

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

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

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

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

悲觀鎖存的問題:

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

樂觀鎖

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

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

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

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

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

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

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

// 假設(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 {
            // 更新失敗,可能是因為其他線程修改了共享資源的值,重試更新操作
            continue;
        }
    } else {
        // 當(dāng)前值不等于舊的預(yù)期值,說明共享資源的值已經(jīng)被其他線程修改,重試更新操作
        continue;
    }
}

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

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

樂觀鎖存在的問題

CAS雖然很?效的解決原?操作,但是CAS仍然存在三?問題:ABA問題自旋時間過長只能保證單個變量的原子性。

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

悲觀鎖和樂觀鎖的對比

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

總結(jié)

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

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

相關(guān)文章

  • Java8中Stream的一些神操作

    Java8中Stream的一些神操作

    Stream是Java8中處理集合的關(guān)鍵抽象概念,它可以指定你希望對集合進行的操作,可以執(zhí)行非常復(fù)雜的查找、過濾和映射數(shù)據(jù)等操作,這篇文章主要給大家介紹了Java8中Stream的一些神操作,需要的朋友可以參考下
    2021-11-11
  • 通過Java代碼來創(chuàng)建view的方法

    通過Java代碼來創(chuàng)建view的方法

    本文給大家分享通過java代碼創(chuàng)建view的方法,以TextView為例創(chuàng)建控件的方法,需要的的朋友參考下吧
    2017-08-08
  • java爬蟲Jsoup主要類及功能使用詳解

    java爬蟲Jsoup主要類及功能使用詳解

    這篇文章主要為大家介紹了java爬蟲Jsoup主要類及功能使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • Java實現(xiàn)讀取resources目錄下的文件路徑的九種方式

    Java實現(xiàn)讀取resources目錄下的文件路徑的九種方式

    本文主要介紹了Java實現(xiàn)讀取resources目錄下的文件路徑的九種方式,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Maven的安裝+配置本地倉庫路徑方式

    Maven的安裝+配置本地倉庫路徑方式

    這篇文章主要介紹了Maven的安裝+配置本地倉庫路徑方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • springboot中swagger快速啟動流程

    springboot中swagger快速啟動流程

    這篇文章主要介紹了springboot中的swagger快速啟動流程,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09
  • Spring動態(tài)代理實現(xiàn)日志功能詳解

    Spring動態(tài)代理實現(xiàn)日志功能詳解

    這篇文章主要為大家詳細介紹了Spring動態(tài)代理實現(xiàn)日志功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Spring開發(fā)核心之AOP的實現(xiàn)與切入點持久化

    Spring開發(fā)核心之AOP的實現(xiàn)與切入點持久化

    面向?qū)ο缶幊淌且环N編程方式,此編程方式的落地需要使用“類”和 “對象”來實現(xiàn),所以,面向?qū)ο缶幊唐鋵嵕褪菍?nbsp;“類”和“對象” 的使用,面向切面編程,簡單的說,就是動態(tài)地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程
    2022-10-10
  • Java多線程 兩階段終止模式Two-Phase Termination Patter

    Java多線程 兩階段終止模式Two-Phase Termination Patter

    這篇文章主要介紹了Java多線程 兩階段終止模式Two-Phase Termination Patter,該模式有兩個角色,分別是Terminator,終止者,負責(zé)接收終止請求,執(zhí)行終止處理,處理完成后再終止自己。TerminationRequester終止請求發(fā)出者,用來向Terminator發(fā)出終止請求,需要的朋友可以參考一下
    2021-10-10
  • java?stream?distinct()如何按一個或多個指定對象字段進行去重

    java?stream?distinct()如何按一個或多個指定對象字段進行去重

    這篇文章主要介紹了java?stream?distinct()如何按一個或多個指定對象字段進行去重問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12

最新評論

卢氏县| 晋中市| 班玛县| 南乐县| 北票市| 资中县| 启东市| 宣武区| 浦城县| 巨野县| 泉州市| 广安市| 义乌市| 甘洛县| 古丈县| 凉城县| 马公市| 玉环县| 大田县| 克山县| 虎林市| 历史| 虞城县| 海口市| 巴里| 沙河市| 桃源县| 呼玛县| 澄城县| 靖州| 旺苍县| 新晃| 长岛县| 聂荣县| 阿鲁科尔沁旗| 衢州市| 柳江县| 江都市| 德惠市| 满洲里市| 抚松县|