浪子归家|Java并发编程-LinkedBlockingDeque详解( 二 )


putLast(E e)方法是将指定的元素插入到双端队列的末尾 , 源码如下:
public void putLast(E e) throws InterruptedException {// 若插入元素为null , 则直接抛出NullPointerException异常if (e == null) throw new NullPointerException();// 将插入节点包装为Node节点Node node = new Node(e);// 获取全局独占锁final ReentrantLock lock = this.lock;lock.lock();try {while (!linkLast(node))notFull.await();} finally {// 释放全局独占锁lock.unlock();}}该方法和putFirst(E e)方法几乎一样 , 不同点在于 , putLast(E e)方法通过调用linkLast(E e)方法来插入节点:
private boolean linkLast(Node node) {// assert lock.isHeldByCurrentThread();// 元素个数超出容量 。 直接返回falseif (count >= capacity)return false;// 获取双向链表的尾节点Node l = last;// 将node设置为尾节点node.prev = l;last = node;// 若first为null , 设置首节点为node节点if (first == null)first = node;else// 更新原尾节点的后继节点l.next = node;++count;// 唤醒阻塞在notEmpty上的线程notEmpty.signal();return true;}若入队成功 , 则linkLast(E e)方法返回true , 否则 , 返回false 。 若该方法返回false , 则当前线程会阻塞在notFull条件上 。
出队pollFirst()方法是获取并移除此双端队列的首节点 , 若不存在 , 则返回null , 源码如下:
public E pollFirst() {// 获取全局独占锁final ReentrantLock lock = this.lock;lock.lock();try {return unlinkFirst();} finally {// 释放全局独占锁lock.unlock();}}移除首节点的操作是通过unlinkFirst()方法来完成的:
private E unlinkFirst() {// assert lock.isHeldByCurrentThread();// 获取首节点Node f = first;// 首节点为null , 则返回nullif (f == null)return null;// 获取首节点的后继节点Node n = f.next;// 移除first , 将首节点更新为nE item = f.item;f.item = null;f.next = f; // help GCfirst = n;// 移除首节点后 , 为空队列if (n == null)last = null;else// 将新的首节点的前驱节点设置为nulln.prev = null;--count;// 唤醒阻塞在notFull上的线程notFull.signal();return item;}pollLast()方法是获取并移除此双端队列的尾节点 , 若不存在 , 则返回null , 源码如下:
public E pollLast() {// 获取全局独占锁final ReentrantLock lock = this.lock;lock.lock();try {return unlinkLast();} finally {// 释放全局独占锁lock.unlock();}}移除尾节点的操作是通过unlinkLast()方法来完成的:
private E unlinkLast() {// assert lock.isHeldByCurrentThread();// 获取尾节点Node l = last;// 尾节点为null , 则返回nullif (l == null)return null;// 获取尾节点的前驱节点Node p = l.prev;// 移除尾节点 , 将尾节点更新为pE item = l.item;l.item = null;l.prev = l; // help GClast = p;// 移除尾节点后 , 为空队列if (p == null)first = null;else// 将新的尾节点的后继节点设置为nullp.next = null;--count;// 唤醒阻塞在notFull上的线程notFull.signal();return item;}其实LinkedBlockingDeque类的入队、出队操作都是通过linkFirst、linkLast、unlinkFirst、unlinkLast这几个方法来实现的 , 源码读起来也比较简单 。
使用案例import java.util.Date;import java.util.concurrent.LinkedBlockingDeque;import java.util.concurrent.TimeUnit;public class LinkedBlockingDequeTest {public static void main(String[] args) throws Exception {LinkedBlockingDeque linkedBlockingDeque = new LinkedBlockingDeque(10);Thread thread = new Thread(new ClientRequest(linkedBlockingDeque));thread.start();for (; ; ) {String request = linkedBlockingDeque.take();System.out.println("Receive '" + request + "' at " + new Date() + " Size: " + linkedBlockingDeque.size());TimeUnit.SECONDS.sleep(1);}}static class ClientRequest implements Runnable {private LinkedBlockingDeque requestList;public ClientRequest(LinkedBlockingDeque requestList) {this.requestList = requestList;}@Overridepublic void run() {System.out.println("Request start");for (int i = 0; i


推荐阅读