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

多線程-lock與lockInterruptibly的區(qū)別及說(shuō)明

 更新時(shí)間:2025年02月27日 10:08:44   作者:九轉(zhuǎn)成圣  
文章主要討論了Java中ReentrantLock的lock和lockInterruptibly方法的區(qū)別,以及AQS中的雙向鏈表設(shè)計(jì),lock方法不響應(yīng)中斷,而lockInterruptibly方法會(huì)響應(yīng)中斷,AQS的雙向鏈表設(shè)計(jì)使得線程管理更加高效和靈活,適用于高并發(fā)場(chǎng)景

多線程lock與lockInterruptibly區(qū)別

在多線程編程中,鎖(Lock)是用來(lái)確保多個(gè)線程在訪問(wèn)共享資源時(shí)能夠保持一致性和正確性的關(guān)鍵工具。

Java 提供了多種實(shí)現(xiàn)鎖的機(jī)制,其中最常用的是 ReentrantLockReentrantLock 提供了兩種獲取鎖的方法:locklockInterruptibly。

這兩者在處理線程中斷時(shí)表現(xiàn)不同,理解這些差異對(duì)于編寫健壯的多線程程序至關(guān)重要。

lock 方法

示例代碼:

public static void lock() {
    Lock lock = new ReentrantLock();
    try {
        lock.lock();
        Thread t1 = new Thread(() -> {
            Thread currentThread = Thread.currentThread();
            try {
                lock.lock();
                System.out.println(currentThread.getName() + " lock后的代碼");
            } finally {
                lock.unlock();
            }
            System.out.println("currentThread = " + currentThread.getName() + " isInterrupted:" + currentThread.isInterrupted());
        }, "t1");
        t1.start();
        t1.interrupt();
        System.out.println("currentThread = " + Thread.currentThread().getName());
    } finally {
        lock.unlock();
    }
}

執(zhí)行結(jié)果:

currentThread = main
t1 lock后的代碼
currentThread = t1 isInterrupted:true

解釋:

在這個(gè)示例中,主線程(main)首先獲取了鎖。然后啟動(dòng)一個(gè)新線程(t1),該線程嘗試再次獲取同一個(gè)鎖。主線程在啟動(dòng) t1 后立即調(diào)用 t1.interrupt() 方法中斷 t1 線程。

盡管 t1 線程被中斷,它還是成功獲取到了鎖并執(zhí)行了鎖后的代碼。這是因?yàn)?lock 方法在獲取鎖時(shí)不會(huì)理會(huì)線程的中斷狀態(tài),只要鎖可用,它就會(huì)獲取鎖。換句話說(shuō),即使線程被中斷,它也會(huì)繼續(xù)等待獲取鎖,直到成功為止。

lockInterruptibly 方法

示例代碼:

public static void lockInterruptiblyDemo() {
    Lock lock = new ReentrantLock();
    try {
        lock.lock();
        Thread t1 = new Thread(() -> {
            Thread currentThread = Thread.currentThread();
            try {
                lock.lockInterruptibly();
                System.out.println(currentThread.getName() + " lockInterruptibly后的代碼");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            System.out.println("currentThread = " + currentThread.getName() + " isInterrupted:" + currentThread.isInterrupted());
        }, "t1");
        t1.start();
        t1.interrupt();
        System.out.println("currentThread = " + Thread.currentThread().getName());
    } finally {
        lock.unlock();
    }
}

執(zhí)行結(jié)果:

currentThread = main
java.lang.InterruptedException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1220)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
    at Xxx.lambda$lockInterruptiblyDemo$1(Xxx.java:39)
    at java.lang.Thread.run(Thread.java:748)
Exception in thread "t1" java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
    at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
    at Xxx.lambda$lockInterruptiblyDemo$1(Xxx.java:44)
    at java.lang.Thread.run(Thread.java:748)

解釋:

在這個(gè)示例中,t1 線程嘗試獲取鎖時(shí)調(diào)用了 lockInterruptibly 方法。與 lock 方法不同,lockInterruptibly 在嘗試獲取鎖時(shí)會(huì)檢查線程的中斷狀態(tài)。如果線程被中斷,它會(huì)立即拋出 InterruptedException 異常,而不會(huì)繼續(xù)等待獲取鎖。

執(zhí)行結(jié)果顯示,t1 線程在嘗試獲取鎖時(shí)被中斷,并且拋出了 InterruptedException。由于異常被捕獲并打印,t1 線程并沒(méi)有獲取鎖,這避免了在某些情況下可能出現(xiàn)的死鎖問(wèn)題。

區(qū)別總結(jié)

中斷響應(yīng)

  • lock 方法:不響應(yīng)中斷,線程會(huì)一直嘗試獲取鎖,直到成功為止。
  • lockInterruptibly 方法:響應(yīng)中斷,線程在檢測(cè)到中斷后會(huì)拋出 InterruptedException 并停止嘗試獲取鎖。

使用場(chǎng)景

  • lock 方法適用于不需要考慮中斷的場(chǎng)景。
  • lockInterruptibly 方法適用于需要及時(shí)響應(yīng)中斷的場(chǎng)景,例如當(dāng)需要能夠中斷線程來(lái)避免死鎖時(shí)。

面試題:為什么 AQS 中的隊(duì)列設(shè)計(jì)為雙向鏈表?

AQS(AbstractQueuedSynchronizer)是 Java 并發(fā)包中鎖和同步器的基礎(chǔ)框架。AQS 內(nèi)部使用了一個(gè) FIFO(先進(jìn)先出)的雙向鏈表來(lái)管理等待線程的隊(duì)列。

原因:

雙向遍歷

  • 當(dāng)一個(gè)節(jié)點(diǎn)(線程)被喚醒時(shí),需要能方便地找到前驅(qū)節(jié)點(diǎn)以確保線程的喚醒順序和正確性。
  • 雙向鏈表允許從當(dāng)前節(jié)點(diǎn)輕松訪問(wèn)前驅(qū)節(jié)點(diǎn),從而能夠修改前驅(qū)節(jié)點(diǎn)的狀態(tài)。

節(jié)點(diǎn)刪除

  • 在一些情況下,節(jié)點(diǎn)(線程)可能需要從隊(duì)列中取消。
  • 雙向鏈表使得刪除節(jié)點(diǎn)操作更加高效,因?yàn)榭梢灾苯油ㄟ^(guò)前驅(qū)和后繼節(jié)點(diǎn)來(lái)重新鏈接,而不需要從頭遍歷。

狀態(tài)更新

  • 雙向鏈表結(jié)構(gòu)使得更新節(jié)點(diǎn)狀態(tài)(如將節(jié)點(diǎn)從等待狀態(tài)變?yōu)檫\(yùn)行狀態(tài))更為便捷
  • 可以在節(jié)點(diǎn)之間高效地傳播狀態(tài)信息

實(shí)現(xiàn)復(fù)雜性

  • 雖然雙向鏈表在實(shí)現(xiàn)上稍微復(fù)雜一些
  • 但提供的靈活性和操作效率的提升在高并發(fā)場(chǎng)景中是值得的

通過(guò)這種設(shè)計(jì),AQS 能夠更高效地管理線程隊(duì)列,確保鎖和同步器的高性能和正確性。

詳細(xì)分析:AQS 中的雙向鏈表

AQS 是一個(gè)基于節(jié)點(diǎn)的框架,所有等待獲取鎖的線程都會(huì)被封裝成一個(gè)節(jié)點(diǎn)并加入到等待隊(duì)列中。該隊(duì)列的結(jié)構(gòu)和操作直接影響鎖的性能和響應(yīng)能力。

AQS 中的主要節(jié)點(diǎn)結(jié)構(gòu):

每個(gè)節(jié)點(diǎn)包含以下主要部分:

  • 前驅(qū)節(jié)點(diǎn):指向前一個(gè)等待線程的節(jié)點(diǎn)。
  • 后繼節(jié)點(diǎn):指向后一個(gè)等待線程的節(jié)點(diǎn)。
  • 線程引用:包含正在等待獲取鎖的線程的引用。
  • 狀態(tài):表示線程的等待狀態(tài)(如等待、取消等)。

操作示例:

入隊(duì)

  • 當(dāng)一個(gè)線程請(qǐng)求獲取鎖但鎖不可用時(shí),它會(huì)被封裝成一個(gè)節(jié)點(diǎn)并加入到隊(duì)列末尾。
  • 雙向鏈表結(jié)構(gòu)允許快速定位隊(duì)尾并將新節(jié)點(diǎn)鏈接上去。

出隊(duì)

  • 當(dāng)一個(gè)節(jié)點(diǎn)被喚醒時(shí)(通常是獲取到鎖),它需要從隊(duì)列中移除。
  • 雙向鏈表結(jié)構(gòu)允許通過(guò)前驅(qū)和后繼節(jié)點(diǎn)高效地重新鏈接,刪除節(jié)點(diǎn)。

狀態(tài)傳播

  • 當(dāng)一個(gè)節(jié)點(diǎn)狀態(tài)改變時(shí)(如從等待到運(yùn)行),它需要通知前驅(qū)或后繼節(jié)點(diǎn)。
  • 雙向鏈表允許在節(jié)點(diǎn)之間高效地傳播狀態(tài),確保隊(duì)列中的每個(gè)線程都能正確響應(yīng)狀態(tài)變化。

總結(jié)

理解 locklockInterruptibly 的區(qū)別有助于我們?cè)诙嗑€程編程中選擇適當(dāng)?shù)逆i獲取方式,確保程序的健壯性和響應(yīng)能力。而 AQS 中的雙向鏈表設(shè)計(jì)則是確保鎖和同步器高效管理等待線程隊(duì)列的重要基礎(chǔ),這種設(shè)計(jì)使得線程管理更加高效和靈活,在高并發(fā)場(chǎng)景中表現(xiàn)尤為突出。通過(guò)深入理解這些底層機(jī)制,我們可以更好地編寫高性能的多線程應(yīng)用程序。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java文件字符輸入流FileReader讀取txt文件亂碼的解決

    Java文件字符輸入流FileReader讀取txt文件亂碼的解決

    這篇文章主要介紹了Java文件字符輸入流FileReader讀取txt文件亂碼的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java設(shè)計(jì)模式之策略模式案例詳解

    Java設(shè)計(jì)模式之策略模式案例詳解

    策略模式(Strategy?Pattern)定義了一組同類型的算法,在不同的類中封裝起來(lái),每種算法可以根據(jù)當(dāng)前場(chǎng)景相互替換,從而使算法的變化獨(dú)立于使用它們的客戶端即算法的調(diào)用者
    2022-07-07
  • Java?數(shù)據(jù)結(jié)構(gòu)進(jìn)階二叉樹(shù)題集下

    Java?數(shù)據(jù)結(jié)構(gòu)進(jìn)階二叉樹(shù)題集下

    二叉樹(shù)可以簡(jiǎn)單理解為對(duì)于一個(gè)節(jié)點(diǎn)來(lái)說(shuō),最多擁有一個(gè)上級(jí)節(jié)點(diǎn),同時(shí)最多具備左右兩個(gè)下級(jí)節(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)。本文將帶你通過(guò)實(shí)際題目來(lái)熟練掌握
    2022-04-04
  • spring MVC中接口參數(shù)解析的過(guò)程詳解

    spring MVC中接口參數(shù)解析的過(guò)程詳解

    這篇文章主要給大家介紹了關(guān)于spring MVC中接口參數(shù)解析的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用spring mvc具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • @KafkaListener 如何使用

    @KafkaListener 如何使用

    這篇文章主要介紹了@KafkaListener 如何使用,本文通過(guò)圖文實(shí)例代碼相結(jié)合給大家詳細(xì)講解,文末給大家介紹了kafka的消費(fèi)者分區(qū)分配策略,需要的朋友可以參考下
    2023-02-02
  • MyBatis 添加元數(shù)據(jù)自定義元素標(biāo)簽的實(shí)現(xiàn)代碼

    MyBatis 添加元數(shù)據(jù)自定義元素標(biāo)簽的實(shí)現(xiàn)代碼

    這篇文章主要介紹了MyBatis 添加元數(shù)據(jù)自定義元素標(biāo)簽的實(shí)現(xiàn)代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • java實(shí)現(xiàn)表格數(shù)據(jù)的存儲(chǔ)

    java實(shí)現(xiàn)表格數(shù)據(jù)的存儲(chǔ)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)表格數(shù)據(jù)的存儲(chǔ),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • java秒殺之redis限流操作詳解

    java秒殺之redis限流操作詳解

    這篇文章主要為大家詳細(xì)介紹了java秒殺之redis限流操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • SpringBoot中controller深層詳細(xì)講解

    SpringBoot中controller深層詳細(xì)講解

    這篇文章主要介紹了SpringBoot在Controller層接收參數(shù)的常用方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-02-02
  • 利用Intellij Idea連接遠(yuǎn)程服務(wù)器實(shí)現(xiàn)遠(yuǎn)程上傳部署功能

    利用Intellij Idea連接遠(yuǎn)程服務(wù)器實(shí)現(xiàn)遠(yuǎn)程上傳部署功能

    大家在使用Intellij Idea開(kāi)發(fā)程序的時(shí)候,是不是需要部署到遠(yuǎn)程SSH服務(wù)器運(yùn)行呢,當(dāng)然也可以直接在idea軟件內(nèi)容實(shí)現(xiàn)配置部署操作,接下來(lái)通過(guò)本文給大家分享利用Intellij Idea連接遠(yuǎn)程服務(wù)器實(shí)現(xiàn)遠(yuǎn)程上傳部署功能,感興趣的朋友跟隨小編一起看看吧
    2021-05-05

最新評(píng)論