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

java ReentrantLock條件鎖實現(xiàn)原理示例詳解

 更新時間:2023年01月09日 09:39:44   作者:小海編碼日記  
這篇文章主要為大家介紹了java ReentrantLock條件鎖實現(xiàn)原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

在前兩篇文章中,我們了解了ReentrantLock內部公平鎖和非公平鎖的實現(xiàn)原理,可以知道其底層基于AQS,使用雙向鏈表實現(xiàn),同時在線程間通信方式(2)中我們了解到ReentrantLock也是支持條件鎖的,接下來我們來看下,其內部條件鎖的實現(xiàn)原理。

條件鎖的使用

 public static void main(String[] args) {
     ReentrantLock lock = new ReentrantLock();
     Condition condition = lock.newCondition();
     ExecutorService executorService = Executors.newCachedThreadPool();
     executorService.execute(new Runnable() {
         @Override
         public void run() {
             lock.lock();
             System.out.println(Thread.currentThread().getName()+" enter lock first");
             System.out.println(Thread.currentThread().getName()+" await start");
             try {
                 condition.await();
             } catch (InterruptedException e) {
                 throw new RuntimeException(e);
             }
             System.out.println(Thread.currentThread().getName()+" await end");
             lock.unlock();
         }
     });
     executorService.execute(new Runnable() {
         @Override
         public void run() {
             lock.lock();
             System.out.println(Thread.currentThread().getName()+" enter lock first");
             System.out.println(Thread.currentThread().getName()+" start sleep");
             try {
                 Thread.sleep(20000);
             } catch (InterruptedException e) {
                 throw new RuntimeException(e);
             }
             System.out.println(Thread.currentThread().getName()+" end sleep");
             System.out.println(Thread.currentThread().getName()+" signalAll condition");
             condition.signalAll();
             System.out.println(Thread.currentThread().getName()+"signal end");
             lock.unlock();
         }
     });
 }

如上代碼所示,一般情況下我們通過

 Condition condition = lock.newCondition();

創(chuàng)建條件對象,使用condition.await();表示當前線程需要等待條件才能繼續(xù)執(zhí)行,當線程執(zhí)行到此處時,會進入等待隊列等待,直到有另一個線程通過condition.signalAll();condition.signal();喚醒,此時表明當前線程執(zhí)行條件已具備,此時當前線程繼續(xù)執(zhí)行,上述代碼中,當前線程會轉入AQS的同步等待隊列中,去等待搶占lock鎖,其運行結果如下圖所示:

條件鎖一般適用于線程需要具備一定條件后才能正確執(zhí)行的情況。

ReentrantLock.newCondition()

上文看到Condition的創(chuàng)建和基本用法,接下來我們來看下Condition的實現(xiàn)原理,跟蹤ReentrantLock的執(zhí)行代碼如下所示:

?// ReentrantLock.java 
?public Condition newCondition() {
? ? ?return sync.newCondition();
?}
??
?// ReentrantLock內部類Sync中
?final ConditionObject newCondition() {
? ? ?return new ConditionObject();
?}

可以看到newCondition最終返回了一個ConditionObject類的對象,ConditionObject類代碼如下所示:

 // AQS中聲明的ConditionObject
 public class ConditionObject implements Condition, java.io.Serializable {
     private static final long serialVersionUID = 1173984872572414699L;
     private transient Node firstWaiter;
     private transient Node lastWaiter;
     public ConditionObject() { }
     private Node addConditionWaiter() {
     }
     private void doSignal(Node first) {
       .....
     }
     private void doSignalAll(Node first) {
       .....
     }
     private void unlinkCancelledWaiters() {
       .....
     }

相信大家已經(jīng)看出來了,很熟悉的Node鏈表有沒有?其中firstWaiter指向鏈表首位,lastWaiter指向鏈表尾,在該鏈表內維護一個Node的雙向鏈表,結合AQS中實現(xiàn),我們可以猜測出,在condition.await的時候會以當前線程創(chuàng)建Node節(jié)點,隨后以插入條件隊列,隨后當執(zhí)行condition.signal/condition.signalAll時,喚醒在鏈表上的這些節(jié)點,具體實現(xiàn)是不是這樣呢?我們繼續(xù)看

Condition.await

ConditionObject實現(xiàn)的await方法如下所示:

 private Node addConditionWaiter() {
     Node t = lastWaiter;
     // If lastWaiter is cancelled, clean out.
     if (t != null && t.waitStatus != Node.CONDITION) {
         unlinkCancelledWaiters();
         t = lastWaiter;
     }
     Node node = new Node(Thread.currentThread(), Node.CONDITION);
     if (t == null)
         firstWaiter = node;
     else
         t.nextWaiter = node;
     lastWaiter = node;
     return node;
 }
 public final void await() throws InterruptedException {
     if (Thread.interrupted())
         throw new InterruptedException();
     // 以當前線程創(chuàng)建Node對象,并添加值隊尾
     Node node = addConditionWaiter();
     int savedState = fullyRelease(node);
     int interruptMode = 0;
     // 通過LockSupport阻塞線程
     while (!isOnSyncQueue(node)) {
         LockSupport.park(this);
         if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
             break;
     }
     if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
         interruptMode = REINTERRUPT;
     if (node.nextWaiter != null) // clean up if cancelled
         unlinkCancelledWaiters();
     if (interruptMode != 0)
         reportInterruptAfterWait(interruptMode);
 }

Condition.signal

ConditionObject中的signal函數(shù)實現(xiàn)如下所示:

 public final void signal() {
     if (!isHeldExclusively())
         throw new IllegalMonitorStateException();
     Node first = firstWaiter;
     if (first != null)
         // 對隊首節(jié)點喚醒
         doSignal(first);
 }
 private void doSignal(Node first) {
     do {
         // 重置firstWaiter并不斷嘗試喚醒首節(jié)點
         if ( (firstWaiter = first.nextWaiter) == null)
             lastWaiter = null;
         first.nextWaiter = null;
     } while (!transferForSignal(first) &&
              (first = firstWaiter) != null);
 }
 final boolean transferForSignal(Node node) {
     // 嘗試更新節(jié)點的waitStatus
     if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
         return false;
     // 當前線程可以正常執(zhí)行了,將該節(jié)點移入同步等待隊列中,嘗試獲取鎖
     Node p = enq(node);
     int ws = p.waitStatus;
     // 如果可以獲取鎖,則立即喚醒執(zhí)行
     if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
         LockSupport.unpark(node.thread);
     return true;
 }

Condition.signalAll的邏輯與signal基本一致,區(qū)別在于是將在該條件上等待的所有節(jié)點均移入同步等待隊列中。

以上就是java ReentrantLock條件鎖實現(xiàn)原理示例詳解的詳細內容,更多關于java ReentrantLock條件鎖的資料請關注腳本之家其它相關文章!

相關文章

  • 淺談log4j 不打印異常堆棧

    淺談log4j 不打印異常堆棧

    這篇文章主要介紹了淺談log4j 不打印異常堆棧,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02
  • Java線程的三種創(chuàng)建方式

    Java線程的三種創(chuàng)建方式

    這篇文章主要給大家分享的是ava線程的三種創(chuàng)建方式,Thread、Runnable和Thread、Runnable和Thread,想了解具體方式的小伙伴可以參考下面文章內容,希望對你有所幫助
    2021-11-11
  • window系統(tǒng)安裝jdk jre的教程圖解

    window系統(tǒng)安裝jdk jre的教程圖解

    java開發(fā)少不了安裝jdk,jdk可以同時安裝多個版本,只要在項目部署時注意切換版本選擇,下面小編給大家?guī)砹藈indow系統(tǒng)安裝jdk jre的教程圖解,感興趣的朋友一起看看吧
    2018-08-08
  • java?-jar命令及SpringBoot通過java?-jav啟動項目的過程

    java?-jar命令及SpringBoot通過java?-jav啟動項目的過程

    本篇文章將為大家講述關于 SpringBoot 項目工程完成后,是如何通過 java-jar 命令來啟動的,以及介紹 java-jar 命令的詳細內容,對SpringBoot java?-jav啟動過程感興趣的朋友跟隨小編一起看看吧
    2023-05-05
  • springboot日期格式化全局LocalDateTime詳解

    springboot日期格式化全局LocalDateTime詳解

    文章主要分析了Spring Boot中ObjectMapper對象的序列化和反序列化過程,并具體探討了日期格式化問題,通過分析Spring Boot的自動配置類JacksonAutoConfiguration,文章詳細說明了ObjectMapper對象的創(chuàng)建和配置過程
    2025-02-02
  • SpringBoot之攔截器與過濾器解讀

    SpringBoot之攔截器與過濾器解讀

    這篇文章主要介紹了SpringBoot之攔截器與過濾器解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Spring?Data?JPA框架快速入門之自定義Repository接口

    Spring?Data?JPA框架快速入門之自定義Repository接口

    Spring?Data?JPA是Spring基于JPA規(guī)范的基礎上封裝的?套?JPA?應?框架,可使開發(fā)者?極簡的代碼即可實現(xiàn)對數(shù)據(jù)庫的訪問和操作,本篇我們來了解Spring?Data?JPA框架的自定義Repository接口
    2022-04-04
  • 最全Gson使用

    最全Gson使用

    GSON彌補了JSON的許多不足的地方,在實際應用中更加適用于Java開發(fā),本文主要介紹了最全Gson使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-05-05
  • 詳解Mybatis中的CRUD

    詳解Mybatis中的CRUD

    這篇文章主要介紹了Mybatis中的CRUD的相關知識,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • 一文搞懂JAVA 枚舉(enum)

    一文搞懂JAVA 枚舉(enum)

    這篇文章主要介紹了JAVA 枚舉(enum)的相關資料,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-07-07

最新評論

淅川县| 雅江县| 徐州市| 韶山市| 威信县| 阿图什市| 额济纳旗| 泸西县| 沂水县| 石楼县| 柳林县| 峡江县| 洛阳市| 绿春县| 胶南市| 临澧县| 山东省| 建阳市| 海伦市| 台中市| 岳普湖县| 东安县| 长乐市| 宝应县| 辽宁省| 曲松县| 瑞昌市| 香河县| 涞水县| 庄河市| 华容县| 宁晋县| 通州市| 桂平市| 浙江省| 伊宁县| 丹阳市| 天台县| 博湖县| 汤阴县| 道孚县|