LinkedBlockingQueue有界佇列
初始化
建立的時候,實際就是指定了佇列大小 capacity,然後佇列node其實就是個單向列表結構,item 是當前元素,next 是下一個元素的引用。預設head指標和last指標都是指向這個空節點。ps: 是不是有點責任鏈模式的感覺呢。
put
put 從佇列尾部插入節點
1. 首先也是獲取到了 ReentrantLock 鎖 ,進行 putLock 加鎖。
2. 新增元素之前,先 while (count.get() == capacity) 判斷一下,count 是佇列中的個數,capacity 是指定的最大個數。相等就說明佇列滿了,那當前執行緒就要park掛起釋放鎖。
3. enqueue(node) 這個是核心,走到這裡說明可以新增元素了。 "last = last.next = node;" 這行程式碼的意思就是先將 last.next 的指標指向node,然後再把 last 也指向它,說明是最後一個元素(初始化的時候我們把 head last 都是指向null這個頭節點的嘛,現在頭節點還是保持不動)。
4. c 是此次put前的元素個數,然後count自增1了。c + 1 < capacity 說明佇列沒有滿,也嘗試去喚醒阻塞的佇列 (這種程式碼確實可讀性不太好,像hashmap裡面也是大量這樣的程式碼)。
5. c == 0 ,表示之前佇列位空,說明可能有執行緒執行take操作被阻塞住了
take
take 從頭部彈出節點
1. 先獲取到 ReentrantLock 鎖 ,進行 takeLock 加鎖。
2. while (count.get() == 0)那就說明佇列中沒有元素,然後把自己掛起來一直等待(前面不是說了put也會喚醒等待的元素嘛,那個時候就會喚醒這個執行緒)。
3. dequeue();就是彈出第一個節點
4. c = count.getAndDecrement(); 首先是c = count的,然後 count-1 ,也就是說 c-count=1
5. c > 1,也就是說task之前起碼是有2個執行緒等待的,現在 dequeue() 之後起碼還有一條資料,那就去喚醒執行緒
6. c == capacity,就是說 take 之前滿了,那就很可能有人put的時候阻塞了,現在就去嘗試喚醒它
。