Java Review - 并发编程_LinkedBlockingQueue原理源码剖析
文章目錄
- 概述
- 類圖結構
- 主要方法
- offer操作
概述
Java Review - 并發編程_ConcurrentLinkedQueue原理&源碼剖析
介紹了使用CAS算法實現的非阻塞隊列ConcurrentLinkedQueue,下面我們來介紹使用獨占鎖實現的阻塞隊列LinkedBlockingQueue
類圖結構
首先看一下LinkedBlockingQueue的類圖結構,以便從全局對LinkedBlockingQueue有個直觀的了解
-
由類圖可以看到,LinkedBlockingQueue也是使用單向鏈表實現的,其也有兩個Node,分別用來存放首、尾節點,并且還有一個初始值為0的原子變量count,用來記錄隊列元素個數。
-
另外還有兩個ReentrantLock的實例,分別用來控制元素入隊和出隊的原子性,其中takeLock用來控制同時只有一個線程可以從隊列頭獲取元素,其他線程必須等待,putLock控制同時只能有一個線程可以獲取鎖,在隊列尾部添加元素,其他線程必須等待
-
另外,notEmpty和notFull是條件變量,它們內部都有一個條件隊列用來存放進隊和出隊時被阻塞的線程,其實這是生產者—消費者模型
-
當調用線程在LinkedBlockingQueue實例上執行take、 poll等操作時需要獲取到takeLock鎖,從而保證同時只有一個線程可以操作鏈表頭節點。另外由于條件變量notEmpty內部的條件隊列的維護使用的是takeLock的鎖狀態管理機制,所以在調用notEmpty的await和signal方法前調用線程必須先獲取到takeLock鎖,否則會拋出IllegalMonitorStateException異常。notEmpty內部則維護著一個條件隊列,當線程獲取到takeLock鎖后調用notEmpty的await方法時,調用線程會被阻塞,然后該線程會被放到notEmpty內部的條件隊列進行等待,直到有線程調用了notEmpty的signal方法。
-
在LinkedBlockingQueue實例上執行put、offer等操作時需要獲取到putLock鎖,從而保證同時只有一個線程可以操作鏈表尾節點。同樣由于條件變量notFull內部的條件隊列的維護使用的是putLock的鎖狀態管理機制,所以在調用notFull的await和signal方法前調用線程必須先獲取到putLock鎖,否則會拋出IllegalMonitorStateException異常。notFull內部則維護著一個條件隊列,當線程獲取到putLock鎖后調用notFull的await方法時,調用線程會被阻塞,然后該線程會被放到notFull內部的條件隊列進行等待,直到有線程調用了notFull的signal方法。
如下是LinkedBlockingQueue的無參構造函數的代碼。
/*** A constant holding the maximum value an {@code int} can* have, 2<sup>31</sup>-1.*/@Native public static final int MAX_VALUE = 0x7fffffff;/*** Creates a {@code LinkedBlockingQueue} with a capacity of* {@link Integer#MAX_VALUE}.*/public LinkedBlockingQueue() {this(Integer.MAX_VALUE);}public LinkedBlockingQueue(int capacity) {if (capacity <= 0) throw new IllegalArgumentException();this.capacity = capacity;// 初始化首 尾節點,并讓它指向哨兵節點last = head = new Node<E>(null);}由該代碼可知,默認隊列容量為0x7fffffff,用戶也可以自己指定容量,所以從一定程度上可以說LinkedBlockingQueue是有界阻塞隊列。
主要方法
offer操作
總結
以上是生活随笔為你收集整理的Java Review - 并发编程_LinkedBlockingQueue原理源码剖析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java Review - 并发编程_S
- 下一篇: Java Review - 并发编程_A