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

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

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

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

在多線程編程中,鎖(Lock)是用來確保多個線程在訪問共享資源時能夠保持一致性和正確性的關鍵工具。

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

這兩者在處理線程中斷時表現(xià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í)行結果:

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

解釋:

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

盡管 t1 線程被中斷,它還是成功獲取到了鎖并執(zhí)行了鎖后的代碼。這是因為 lock 方法在獲取鎖時不會理會線程的中斷狀態(tài),只要鎖可用,它就會獲取鎖。換句話說,即使線程被中斷,它也會繼續(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í)行結果:

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)

解釋:

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

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

區(qū)別總結

中斷響應

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

使用場景

  • lock 方法適用于不需要考慮中斷的場景。
  • lockInterruptibly 方法適用于需要及時響應中斷的場景,例如當需要能夠中斷線程來避免死鎖時。

面試題:為什么 AQS 中的隊列設計為雙向鏈表?

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

原因:

雙向遍歷

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

節(jié)點刪除

  • 在一些情況下,節(jié)點(線程)可能需要從隊列中取消。
  • 雙向鏈表使得刪除節(jié)點操作更加高效,因為可以直接通過前驅和后繼節(jié)點來重新鏈接,而不需要從頭遍歷。

狀態(tài)更新

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

實現(xiàn)復雜性

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

通過這種設計,AQS 能夠更高效地管理線程隊列,確保鎖和同步器的高性能和正確性。

詳細分析:AQS 中的雙向鏈表

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

AQS 中的主要節(jié)點結構:

每個節(jié)點包含以下主要部分:

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

操作示例:

入隊

  • 當一個線程請求獲取鎖但鎖不可用時,它會被封裝成一個節(jié)點并加入到隊列末尾。
  • 雙向鏈表結構允許快速定位隊尾并將新節(jié)點鏈接上去。

出隊

  • 當一個節(jié)點被喚醒時(通常是獲取到鎖),它需要從隊列中移除。
  • 雙向鏈表結構允許通過前驅和后繼節(jié)點高效地重新鏈接,刪除節(jié)點。

狀態(tài)傳播

  • 當一個節(jié)點狀態(tài)改變時(如從等待到運行),它需要通知前驅或后繼節(jié)點。
  • 雙向鏈表允許在節(jié)點之間高效地傳播狀態(tài),確保隊列中的每個線程都能正確響應狀態(tài)變化。

總結

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

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

相關文章

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

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

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

    Java設計模式之策略模式案例詳解

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

    Java?數(shù)據(jù)結構進階二叉樹題集下

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

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

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

    @KafkaListener 如何使用

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

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

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

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

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

    java秒殺之redis限流操作詳解

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

    SpringBoot中controller深層詳細講解

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

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

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

最新評論