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

Java常見的鎖策略圖文詳解(附實例代碼)

 更新時間:2025年10月23日 09:41:20   作者:Jul1en_  
Java中的鎖方法是指通過特定的機制來確保多線程環(huán)境下對共享資源的互斥訪問,以避免數(shù)據(jù)不一致和競態(tài)條件,這篇文章主要介紹了Java常見鎖策略的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

常見的鎖策略

樂觀鎖 & 悲觀鎖

加鎖的時候預(yù)測這個鎖出現(xiàn)競爭性的可能性大還是???

預(yù)測這個鎖出現(xiàn)競爭可能性小 —— 樂觀鎖

預(yù)測這個鎖出現(xiàn)競爭可能性大 —— 悲觀鎖

輕量級鎖 & 重量級鎖

加鎖的開銷小 —— 輕量級鎖

加鎖的開銷大 —— 重量級鎖

自旋鎖 & 掛起等待鎖

遇到鎖沖突,先不著急阻塞,而是嘗試重新得到鎖。這個操作不涉及內(nèi)核態(tài),僅在用戶態(tài)方面進(jìn)行,所以更加輕量 —— 自旋鎖

遇到鎖沖突,阻塞等待,等到合適的時機再拿鎖。涉及到系統(tǒng)的內(nèi)部調(diào)度,開銷大 —— 掛起等待鎖

公平鎖 & 非公平鎖

JVM約定了“先來后到” 是公平鎖(先請求得到鎖的線程會得到鎖)

“公平競爭,各憑本事”是不公平鎖(解鎖后,多個線程同時競爭一把鎖)

可重入鎖 & 不可重入鎖

一個線程,一把鎖,同時加鎖兩次

如果沒死鎖:可重入鎖;死鎖了:不可重入鎖

C++的std :: mutex 是不可重入鎖

可重入鎖也稱“可遞歸鎖”

synchronized是可重入鎖,以第一次加鎖為真,第二次加鎖跳過

普通互斥鎖 & 讀寫鎖

普通互斥鎖有

  • 加鎖
  • 解鎖

讀寫鎖有

  • 加讀鎖
  • 加寫鎖
  • 解鎖

如果代碼中線程進(jìn)行讀的操作,那可以使用“讀鎖”,寫的操作使用“寫鎖”

讀鎖與讀鎖之間不存在互斥 —— 讀的過程數(shù)據(jù)不會發(fā)生改變,只是讀

讀鎖與寫鎖之間存在互斥 —— 讀的過程中可能會被“寫”修改

寫鎖與寫鎖之間存在互斥 —— A寫的時候肯定不能被B修改

synchronized鎖

synchronized鎖是普通互斥鎖,是可重入鎖,是非公平鎖,有著自適應(yīng)的特點,根據(jù)內(nèi)部鎖競爭的激烈程度,自動調(diào)整內(nèi)部策略,感知不到,干預(yù)不了,但我們需要知道內(nèi)部策略細(xì)節(jié)

鎖升級

鎖消除

針對synchronized的一種編譯器優(yōu)化,在保證邏輯不變的情況下,如果編譯器確定你寫的代碼不需要鎖,但你手動加了鎖,會嘗試把鎖去掉。

但這個優(yōu)化十分保守,沒有十拿九穩(wěn)的情況下不會觸發(fā),我們也不能依賴編譯器優(yōu)化這個機制來寫代碼

鎖粗化

關(guān)聯(lián)到鎖的粒度,編譯器會根據(jù)實際情況來操作

如果鎖的粒度小,證明加鎖解鎖中間的邏輯少,雖然會留出時間給其他的線程來得到鎖,但也增加了線程競爭的次數(shù),也會增加阻塞的時間。

鎖的粒度雖然大,但是中間執(zhí)行的邏輯時間長,沒有反復(fù)加鎖解鎖的操作,其他線程也只能競爭一次。

CAS

Compare And Swap

解決線程安全,加鎖是一種普遍的策略,CAS是解決線程安全問題的另一種思路

顧名思義 比較與交換 —— 比較一個內(nèi)存與一個寄存器內(nèi)部的值,如果他兩的值相同,內(nèi)存會與寄存器另外一個值進(jìn)行交換,交換后更關(guān)心內(nèi)存更新之后的值,就可以實現(xiàn)“鎖”的功能

這是CAS的執(zhí)行邏輯

上述針對CAS的執(zhí)行邏輯,能看出它并不是函數(shù),而是一條CPU指令,而且是原子的,那JVM如何運行的呢?

  1. CPU提供了CAS的執(zhí)行指令
  2. 操作系統(tǒng)對CAS指令進(jìn)行了封裝并提供了API,通過API可以調(diào)用CAS機制
  3. JVM就可以通過操作系統(tǒng)調(diào)用API
  4. 我們的代碼就可以使用CAS
  5. Java對CAS進(jìn)一步封裝,Java不建議你用CAS,但內(nèi)部像==原子類==、自旋鎖、synchronized,ConcurrentHashMap都使用了CAS

這又引申出了**原子類**

原子類

內(nèi)部沒有加鎖,但基于CAS實現(xiàn)了,所以不加鎖也能保證線程安全

可以實例化原子類的整數(shù)/字符…,并設(shè)定初始化的值

方法與注釋中的操作是一一對應(yīng)的,舉例getAndIncrement 是先得到舊值,再Increment(+1)

自旋鎖

synchronized內(nèi)部的自旋鎖,就是基于CAS實現(xiàn),這就是為什么自旋鎖輕量的原因(“無鎖”)

ABA問題

CAS的循環(huán)檢測,判定是否有其他線程穿插修改執(zhí)行的依據(jù)是循環(huán)判定是檢測的值是否有變化,但是這種檢測方式是不嚴(yán)謹(jǐn)?shù)模瑳]有變化不能代表沒有被修改過,可能某時刻的值是A,在下一時刻被修改了B,然后在第二次檢測之前又被修改回了A,這就是ABA問題

大部分時候ABA問題不會引起bug,但在某些極端的情況下是會的,就像買新手機一樣,你買的手機是“翻新機”,但翻新機不代表一定就有問題,只是說翻新機出現(xiàn)問題的概率比全新機更大的~

ABA的核心是:
在通過A的值相同判定是否有插隊,由于次數(shù)的修改有加也有減,就可能會出現(xiàn)ABA的問題,那么有一些解決方案:限制此處的操作(只能加或者只能減)、或者引入“版本號”概念,每次修改都讓“版本號”+1,再次使用判定的時候就不是用值來判定了,而是看版本號

那我們可以引申出以下問題??

  1. CAS是什么?
  2. CAS有什么應(yīng)用場景(CAS如何實現(xiàn)鎖)?
  3. CAS的ABA問題是怎么樣的

JUC包中常見的類

JUC——Java.util.Concurrent

Callable接口

是泛型接口,描述一個任務(wù),唯一方法call()?

  • 可以返回一個結(jié)果
  • 可以拋出受檢異常

類似與Runnable,但與Runnable的void run() 不同的是Callable的 V call() throws Exception 有返回值,通常Callable任務(wù)會被交給FutureTaskExecutorService.submit()來執(zhí)行

		Callable<Integer> callable = new Callable<Integer>() {
     		int sum = 0;
            @Override
            public Integer call() throws Exception {
                for (int i = 1; i <= 1000; i++) {
                    sum += i;
                }
                return sum;
            }
        };
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread t = new Thread(futureTask);

FutureTask & Callable 的聯(lián)系

  1. Callable是一個接口,類似與Runnable,但有返回值,并且能拋出受檢異常

    • 使用場景:需要執(zhí)行一個有返回值的任務(wù)時
  2. FutureTask是一個類

    • 實現(xiàn)了RunnableFuture 接口

      ?public class FutureTask<V> implements RunnableFuture<V>?

    • 而RunnableFuture 又繼承了Runnable 和 Future

      ?public interface RunnableFuture<V> extends Runnable, Future<V> { void run(); }?

    • 所以FutureTask既是一個任務(wù)Runnable,也是一個容器Future?

    • 它內(nèi)部持有Callable,并在run()方法中調(diào)用Callable的call()方法

他們的call()/ run()和線程的run()關(guān)系
  1. ?Callable.call()?

    • 是用戶定義的邏輯,可以返回,可以拋出受檢異常
    • 不能直接交給Thread運行,因為它不是Runnable,Thread只能運行Runnable?
  2. ?FutureTask.run()?

    • Runnable的實現(xiàn)
    • 內(nèi)部會調(diào)用Callable.call(),并把結(jié)果存起來,通過.get()得到
  3. ?Thread.run()?

    • Thread本身的run()是空的,當(dāng)你傳入一個Runnable后它才會調(diào)用Runnable.run()?
    • 如果傳入的是FutureTask,則會調(diào)用FutureTask.run(),再通過FutureTask.run()來調(diào)用Callable.call()?

執(zhí)行鏈條:

  1. ?Thread.run() -> Runnable.run()?
  2. ?Thread.run() -> FutureTask.run() -> Callable.call()?

ExecutorService & Callable

?ExecutorService.submit(Callable)不會直接調(diào)用Callable.call(),而是間接調(diào)用

  1. newTaskFor(task)

    • 會把 Callable 包裝成一個 FutureTaskRunnableFuture 的實現(xiàn)類)。
    • 這樣它既是一個 Runnable(能被線程池執(zhí)行),又是一個 Future(能保存結(jié)果)。
  2. execute(ftask)

    • 線程池把 FutureTask 當(dāng)作 Runnable,交給工作線程運行。
    • 線程執(zhí)行時,會調(diào)用 FutureTask.run()。
  3. FutureTask.run()

    • 內(nèi)部調(diào)用 callable.call() 來真正執(zhí)行你的邏輯,并把結(jié)果存起來。

執(zhí)行鏈條:

ExecutorService.submit(Callable)

  1. -> newTaskFor(Callable) (Callable -> FutureTask)
  2. -> execute(FutureTask)
  3. -> Worker(Thread) 執(zhí)行
  4. -> FutureTask.run()
  5. -> Callable.call()

對比Runnable,用Callable的優(yōu)勢

  1. 有返回值

    • ?Runnable.run()沒有返回值
    • ?Callable.call()有返回值,結(jié)合Future/FutureTask使用,就能拿到異步計算的結(jié)果

    優(yōu)點:適合計算類任務(wù),例如“統(tǒng)計一批文件的大小”“并行計算求和”等

  2. 可以拋出受檢異常

    • Runnable不能拋出受檢異常,有異常只能自己捕獲或者包裝成RuntimeException
    • Callable可以拋出受檢異常,并保存到Future中,調(diào)用get()再拋出

    優(yōu)點:讓異常處理邏輯更加自然,避免任務(wù)里硬編碼try-catch

  3. 和并發(fā)框架集成好

    • ExecutorService.submit(Callable task)會返回一個Future,可以用來

      • 獲取結(jié)果:future.get()?
      • 取消任務(wù):future.cancel(true)?
      • 檢查狀態(tài):future.isDone()?

    優(yōu)點:和Runnable相比,更合適在生產(chǎn)級并發(fā)框架應(yīng)用(線程池,F(xiàn)orkJoinPool)

  4. 支持函數(shù)式編程(lambda)

    • Callable是函數(shù)式接口,支持lambda表達(dá)式

      ?Callable<Integer> task = () -> 42;?

    優(yōu)點:代碼更加簡潔美觀

ReentrantLock可重入鎖

一個可重入互斥lock具有與使用synchronized方法和語句訪問的隱式監(jiān)視鎖相同的基本行為和語義,但具有擴展功能。

在上古時期的時候還沒有synchronized,當(dāng)時java的加鎖就是用的ReentrantLock

  1. 支持trylock

    嘗試加鎖,如果加鎖失敗,就直接返回(放棄),也支持指定超時時間

  2. 支持公平鎖

  3. 等待通知機制

    • synchronized.wait()搭配notify(),只支持隨機喚醒或喚醒全部
    • ReentrantLock搭配Condition類,喚醒功能更加豐富,能指定喚醒

與synchronized區(qū)別

相同點:

  1. synchronized 和 ReentrantLock 都是 Java 中提供的可重入鎖

不同點:

  1. 用法不同:synchronized 可以用來修飾普通方法、靜態(tài)方法和代碼塊;ReentrantLock 只能用于代碼塊;
  2. 獲取和釋放鎖的機制不同:進(jìn)入synchronized 塊自動加鎖和執(zhí)行完后自動釋放鎖; ReentrantLock 需要顯示的手動加鎖和釋放鎖;
  3. 鎖類型不同:synchronized 是非公平鎖; ReentrantLock 默認(rèn)為非公平鎖,也可以手動指定為公平鎖;
  4. 響應(yīng)中斷不同:synchronized 不能響應(yīng)中斷;ReentrantLock 可以響應(yīng)中斷,可用于解決死鎖的問題;
  5. 底層實現(xiàn)不同:synchronized 是 JVM 層面通過監(jiān)視器實現(xiàn)的;ReentrantLock 是基于 AQS 實現(xiàn)的。

‍總結(jié)

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

相關(guān)文章

  • Java日常練習(xí)題,每天進(jìn)步一點點(53)

    Java日常練習(xí)題,每天進(jìn)步一點點(53)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-08-08
  • Swagger3.0 整合spring boot2.7x避免swagger2.0與boot2.7沖突問題

    Swagger3.0 整合spring boot2.7x避免swagger2.0與boot2.7沖突

    這篇文章主要介紹了Swagger3.0 整合spring boot2.7x避免swagger2.0與boot2.7沖突問題,通過注釋掉2.0引入的倆包,直接引入3.0,文中結(jié)合實例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2023-10-10
  • Java內(nèi)存模型final的內(nèi)存語義

    Java內(nèi)存模型final的內(nèi)存語義

    這篇文章主要介紹了Java內(nèi)存模型final的內(nèi)存語義,上篇介紹volatile的內(nèi)存語義,本文講述的是final的內(nèi)存語義,相比之下,final域的讀和寫更像是普通變量的訪問。下面我們一起來看看文章學(xué)校內(nèi)容吧,需要的朋友可以參考一下
    2021-11-11
  • Intellij idea熱部署插件JRebel的使用

    Intellij idea熱部署插件JRebel的使用

    這篇文章主要介紹了Intellij idea熱部署插件JRebel的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Java中Bigdecimal類的toString()方法和toPlainString()方法區(qū)別

    Java中Bigdecimal類的toString()方法和toPlainString()方法區(qū)別

    BigDecimal類有多個方法可以將其轉(zhuǎn)換為字符串,其中包括toString()和toPlainString(),本文主要介紹了Java中Bigdecimal類的toString()方法和toPlainString()方法區(qū)別,具有一定的參考價值,感興趣的可以了解一下
    2024-07-07
  • Spring?Boot+Vue實現(xiàn)Socket通知推送的完整步驟

    Spring?Boot+Vue實現(xiàn)Socket通知推送的完整步驟

    最近工作中涉及消息通知功能的開發(fā),所以下面這篇文章主要給大家介紹了關(guān)于Spring?Boot+Vue實現(xiàn)Socket通知推送的完整步驟,文中通過實例代碼以及圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • java驗證用戶是否已經(jīng)登錄 java實現(xiàn)自動登錄

    java驗證用戶是否已經(jīng)登錄 java實現(xiàn)自動登錄

    這篇文章主要介紹了java驗證用戶是否已經(jīng)登錄,java實現(xiàn)自動登錄,感興趣的小伙伴們可以參考一下
    2016-04-04
  • springboot?@Async?注解如何實現(xiàn)方法異步

    springboot?@Async?注解如何實現(xiàn)方法異步

    這篇文章主要介紹了springboot?@Async?注解如何實現(xiàn)方法異步,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 一篇文章帶你了解Java方法的使用

    一篇文章帶你了解Java方法的使用

    這篇文章主要給大家介紹了關(guān)于Java中方法使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08
  • Java Spring 中 @PostConstruct 注解使用原理及常見場景

    Java Spring 中 @PostConstruct 注解使用原理及常見場景

    在 Java Spring 中,@PostConstruct 注解是一個非常實用的功能,它允許開發(fā)者在 Spring 容器完全初始化 Bean 后執(zhí)行某些操作,本文將詳細(xì)介紹 @PostConstruct 注解的使用,包括其原理、常見場景和代碼示例,
    2025-04-04

最新評論

铜鼓县| 玉山县| 青河县| 四子王旗| 巨野县| 金昌市| 日照市| 赫章县| 康乐县| 武平县| 桓台县| 汝阳县| 襄城县| 长春市| 桐柏县| 逊克县| 错那县| 资溪县| 如东县| 蓝田县| 青岛市| 康保县| 南溪县| 汉寿县| 闻喜县| 略阳县| 托克托县| 达日县| 威信县| 贵定县| 蚌埠市| 南充市| 大同县| 芜湖县| 汉寿县| 柯坪县| 桓台县| 汉寿县| 边坝县| 四川省| 涞源县|