LinkedBlockingQueue

接ArrayBlockingQueue,這里我談下我對LinkedBlockingQueue的理解。

由阻塞隊列的ArrayBlockingQueue和LinkedBlockingQueue,我們很容易聯想到List的兩種實現:ArrayList和LinkedList。ArrayList與ArrayBlockingQueue相似,底層都使用了數組,同樣LinkedList和LinkedBlockingQueue也類似,底層使用了鏈表。不過這里的鏈表還是有些許不同的:

1. LinkedList使用了雙向鏈表,而LinkedBlockingQueue使用了單向鏈表。

2. LinkedList的容量理論上是無限的,而LinkedBlockingQueue卻是有限的。

讓我們來看看構造函數:

構造函數

無參構造函數實際上創建了一個大小為Integer.MAX_VALUE,而有參構造函數傳入的也是int。也就是說其實LinkedBlockingQueue是有界的。

接下來,我們看看它所使用的鎖。

從代碼中可以看出,它有兩個鎖,一個takeLock(讀鎖),一個putLock(寫鎖)。這與ArrayBlockingQueue是不一樣的。ArrayBlockingQueue只有一個鎖。為什么有這樣的差異呢?ArrayBlockingQueue底層使用了數組,存儲空間是連續的,讀寫同一片存儲空間,而且可能涉及到元素的移動,只能用同一把鎖來控制訪問,而LinkedBlockingQueue使用的是鏈表,存儲空間是不連續的,元素的異動只是指針的變更,讀寫鎖自然可以分離。

兩個Condition分別使用在不同場景下:

notEmpty和takeLock搭配,獲取了takeLock還不夠,還必須滿足notEmpty的條件。

notFull和putLock搭配,獲取了putLock還不夠,還必須滿足notFull的條件。

再來看看put方法。

put方法
enqueue方法

代碼比較簡單明了,只說三點:

1. 不允許Null值存入鏈表。

2. 入隊enqueue方法有兩步,第一,把尾指針的next指向新加入的Node,第二,把尾指針重新指向新加入的Node。這個方法是線程安全的,因為它是在獲得lock后執行的

3. 局部變量c是從-1開始的,代表元素還沒有成功設置。

類似的,我們也可以分析take方法,這里就不在贅述。可以稍微看下出隊的方法。

dequeue方法

首先,把頭結點的next指向自己,這樣就沒有GC Roots可達了,接著把第一個節點元素置空,好騰出來做頭結點。最后返回置空前的元素值。

LinkedBlockingQueue就分析到這里。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容