阻塞佇列原始碼閱讀記錄

2021-08-28 19:18:13 字數 1758 閱讀 8786

本文結合生產者消費者模式對阻塞佇列的主要方法實現進行說明。

該佇列維護的臨界區由鍊錶實現,主要成員變數如下:

capacity:臨界區的上限

count:原子整型,臨界區的實際大小

head:指向隊首節點,控制出隊過程

tail:指向隊尾節點,控制入隊過程

notempty:非空等待條件,從臨界區中取資源時,若無資源則在該條件上等待

takelock:控制每次只有乙個執行緒從臨界區中取資源

notfull:非滿等待條件,往臨界區中存資源時,若無空位(資源數量已經達到上限)則在該條件上等待

putlock:控制每次只有乙個執行緒往臨界區中存資源

主要步驟為:

1.判斷臨界區中是否有資源,若無則在notempty條件上等待,否則進入2

2.通過臨界區鍊錶的頭指標head將隊首資源出隊,資源計數count減一

3.若take操作之前資源數等於資源上限,則說明此次操作後臨界區中將有空位存在,此時喚醒等待在notfull條件上的執行緒

public e take() throws interruptedexception 

x = dequeue();

c = count.getanddecrement();

//當多個消費者執行緒因臨界區中無資源,而在notempty上阻塞時,若某個生產者執行緒呼叫put方法往臨界區中存資源,該執行緒將呼叫notempty.signal喚醒阻塞的消費者執行緒,但只會喚醒乙個執行緒(不會呼叫signalall,因為只增加了乙個資源,若將阻塞消費者執行緒全部喚醒,大部分執行緒還是會因搶不到資源而繼續阻塞,這樣產生了無意義的上下文切換)

//消費者取資源後,若臨界區中還有資源,則鏈式喚醒其他的消費者

if (c > 1)

notempty.signal();

} finally

//若取資源之前,資源數達到上限,說明此次取出後臨界區中存在空位,此時喚醒乙個阻塞的生產者

//為什麼c < capacity時不喚醒生產者,因為c == capacity時只要喚醒了某個生產者,該生產者每次生產資源後會判斷臨界區中的資源數,若未達到上限,則鏈式喚醒其他生產者

//這樣同樣保證了阻塞的執行緒必定有機會被喚醒,另外消費者呼叫signalnotfull方法去喚醒生產者,需要加鎖和解鎖,而生產者呼叫notfull.signal喚醒生產者時,已經獲取了鎖,不必進行額外的加解鎖操作

if (c == capacity)

signalnotfull();

return x;

}

put方法,往臨界區中存資源(生產者生產資源),與take方法基本對稱

該佇列維護的臨界區由陣列實現,與linkedblockingqueue的主要區別為該佇列只有一把鎖,直接鎖住整個陣列,因此所有操作均為序列,首尾指標由陣列和首尾索引代替,陣列為「迴圈陣列」

很簡單的判斷臨界區資源數量,決定是否阻塞,count保證了隊尾索引無論如何「前移」,均不會超越隊尾指標

入隊時插入資源,隊尾索引」前移「

出隊時置當前隊首索引處資源為空,隊首索引「前移」

public e take() throws interruptedexception  finally 

}public void put(e e) throws interruptedexception finally

}

mybatis原始碼閱讀記錄

深入淺出mybatis 技術原理與實戰 楊開振著 大體結構 sqlsessionfactory defaultsqlsessionfactory 構建sqlsession configuration xml檔案的記憶體表達 sqlsession下的四個物件 executor 執行器,用來排程stat...

《原始碼閱讀》原始碼閱讀技巧,原始碼閱讀工具

檢視某個類的完整繼承關係 選中類的名稱,然後按f4 quick type hierarchy quick type hierarchy可以顯示出類的繼承結構,包括它的父類和子類 supertype hierarchy supertype hierarchy可以顯示出類的繼承和實現結構,包括它的父類和...

mybatis之原始碼閱讀記錄

使用mybatis已經有幾年了,之前只是在專案中配置和使用,但是沒有去追究它的內部實現的細節,後來也償試去學習原始碼,看過一些文章,但是不得入門。後來在mybatis官網的入門指引找找到了靈感,終於對mybatis的實現有了一定的理解 在mybatis的官網上介紹了我們在不依賴spring類容器的情...