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的时候阻塞了,现在就去尝试唤醒它

 

原文地址:https://www.cnblogs.com/wlwl/p/15057170.html