3 构造方法
3.1 无参
- 默认为 Integer 的最大值
3.2 有参
- 指定容量大小.链表头尾相等,节点值(item)都是 null
- 已有集合数据
public LinkedBlockingQueue(Collection<? extends E> c) { this(Integer.MAX_VALUE); final ReentrantLock putLock = this.putLock; putLock.lock(); // Never contended, but necessary for visibility try { int n = 0; for (E e : c) { // 集合元素不能为 null if (e == null) throw new NullPointerException(); // capacity 代表链表的大小,在这为 Integer.MAX_VALUE // 若集合大小 > IntegerMAX_VALUE,直接抛异常. if (n == capacity) throw new IllegalStateException("Queue full"); enqueue(new Node<E>(e)); ++n; } count.set(n); } finally { putLock.unlock(); } }
4 新增
以 offer 方法为例,将元素E添加到队列的末尾
public boolean offer(E e) { if (e == null) throw new NullPointerException(); // 如果“队列已满”,则返回false,表示插入失败。 final AtomicInteger count = this.count; if (count.get() == capacity) return false; int c = -1; // 新建“节点e” Node<E> node = new Node(e); final ReentrantLock putLock = this.putLock; // 获取“插入锁putLock” putLock.lock(); try { // 再次对“队列是不是满”的进行判断。 // 若“队列未满”,则插入节点。 if (count.get() < capacity) { // 插入节点 enqueue(node); // 将“当前节点数量”+1,并返回“原始的数量” c = count.getAndIncrement(); // 如果在插入元素之后,队列仍然未满,则唤醒notFull上的等待线程。 if (c + 1 < capacity) notFull.signal(); } } finally { // 释放“插入锁putLock” putLock.unlock(); } // 如果在插入节点前,队列为空;则插入节点后,唤醒notEmpty上的等待线程 if (c == 0) signalNotEmpty(); return c >= 0; }
enqueue
- 将node添加到队列末尾,并设置node为新的尾节点
signalNotEmpty
- 发出等待信号。 仅能从put/offer调用(否则通常不锁定takeLock),唤醒notEmpty上的等待线程.
- 新增数据成功后,在适当时机,会唤起 put 的等待线程(队列不满时),或者 take 的等待线程(队列不为空时),这样保证队列一旦满足 put 或者 take 条件时,立马就能唤起阻塞线程,继续运行,保证了唤起的时机不被浪费。
5 取出
take
以take()为例,取出并返回队列的头。若队列为空,则一直等待。
public E take() throws InterruptedException { E x; int c = -1; final AtomicInteger count = this.count; final ReentrantLock takeLock = this.takeLock; // 获取“取出锁”,若当前线程是中断状态,则抛InterruptedException takeLock.lockInterruptibly(); try { // 若“队列为空”,则一直等待。 while (count.get() == 0) { notEmpty.await(); } // 取元素 x = dequeue(); // 取出元素之后,将“节点数量”-1;并返回“原始的节点数量”。 c = count.getAndDecrement(); if (c > 1) notEmpty.signal(); } finally { // 释放“取出锁” takeLock.unlock(); } // 如果在“取出元素之前”,队列是满的;则在取出元素之后,唤醒notFull上的等待线程。 if (c == capacity) signalNotFull(); return x; }
dequeue
- 删除队列的头节点,并将表头指向“原头节点的下一个节点”。
signalNotFull
- 发出等待的信号。 仅能从take/poll调用.唤醒notFull上的等待线程.