1. 程式人生 > >CountDownLatch共享鎖實現原理

CountDownLatch共享鎖實現原理

CountDownLatch使用解說

CountDownLatch是java5中新增的一個併發工具類,其使用非常簡單,下面通過虛擬碼簡單看一下使用方式:

這裡寫圖片描述

這是一個使用CountDownLatch非常簡單的例子,建立的時候,需要指定一個初始狀態值,本例為2,主執行緒呼叫 latch.await時,除非latch狀態值為0,否則會一直阻塞休眠。當所有任務執行完後,主執行緒喚醒,最終執行列印動作。

以上只是一個最簡單的例子,接著咱們再來看一個,這回,咱們想要在任務執行完後做更多的事情,如下圖所示:

這裡寫圖片描述

這一次,線上程3和執行緒4中,分別呼叫了latch.await(),當latch狀態值為0時,這兩個執行緒將會繼續執行任務,但是順序性是無法保證的。

CountDownLatch的方便之處在於,你可以在一個執行緒中使用,也可以在多個執行緒上使用,一切只依據狀態值,這樣便不會受限於任何的場景。

java共享鎖模型

在java5提供的併發包下,有一個AbstractQueuedSynchronizer抽象類,也叫AQS,此類根據大部分併發共性作了一些抽象,便於開發者實現如排他鎖,共享鎖,條件等待等更高階的業務功能。它通過使用CAS和佇列模型,出色的完成了抽象任務,在此向Doug Lea致敬。

AQS比較抽象,並且是優化精簡的程式碼,如果一頭扎進去,可能會比較容易迷失。本篇只解說CountDownLatch中使用到的共享鎖模型。

我們以CountDownLatch第二個例子作為案例來分析一下,一開始,我們建立了一個CountDownLatch例項,

這裡寫圖片描述

此時,AQS中,狀態值state=2,對於 CountDownLatch 來說,state=2表示所有呼叫await方法的執行緒都應該阻塞,等到同一個latch被呼叫兩次countDown後才能喚醒沉睡的執行緒。接著執行緒3和執行緒4執行了 await方法,這會的狀態圖如下:

這裡寫圖片描述

注意,上面的通知狀態是節點的屬性,表示該節點出隊後,必須喚醒其後續的節點執行緒。當執行緒1和執行緒2分別執行完latch.countDown方法後,會把state值置為0,此時,通過CAS成功置為0的那個執行緒將會同時承擔起喚醒佇列中第一個節點執行緒的任務,從上圖可以看出,第一個節點即為執行緒3,當執行緒3恢復執行之後,其發現狀態值為通知狀態,所以會喚醒後續節點,即執行緒4節點,然後執行緒3繼續做自己的事情,到這裡,執行緒3和執行緒4都已經被喚醒,CountDownLatch功成身退。

上面的流程,如果落實到程式碼,把 state置為0的那個執行緒,會判斷head指向節點的狀態,如果為通知狀態,則喚醒後續節點,即執行緒3節點,然後head指向執行緒3節點,head指向的舊節點會被刪除掉。當執行緒3恢復執行後,發現自身為通知狀態,又會把head指向執行緒4節點,然後刪除自身節點,並喚醒
執行緒4。

這裡可能讀者會有個疑問,執行緒節點的狀態是什麼時候設定上去的。其實,一個執行緒在阻塞之前,就會把它前面的節點設定為通知狀態,這樣便可以實現鏈式喚醒機制了。

結束語

CountDownLatch的實現相對簡單,但卻實現了共享鎖模型原文地址:https://blog.csdn.net/yanyan19880509/article/details/52349056