本文結合生產者消費者模式對阻塞佇列的主要方法實現進行說明。
該佇列維護的臨界區由鍊錶實現,主要成員變數如下:
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類容器的情...