转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/120833494
本文出自【赵彦军的博客】

Java队列 Queue
Java队列 Deque
Java队列 PriorityQueue
Java栈 Stack
Java阻塞队列 LinkedBlockingDeque

文章目录

  • LinkedBlockingDeque
  • 源码
    • 增加操作
    • 删除操作
    • 访问操作
  • BlockingQueue
  • 核心要点
  • 实战

LinkedBlockingDeque

LinkedBlockingDeque类实现了BlockingDeque接口。阅读BlockingDeque文本以获取有关的更多信息。

Deque来自“双端队列” 这个词。Deque是一个队列,你可以在插入和删除队列两端的元素。

LinkedBlockingDeque是一个Deque,如果一个线程试图从中获取一个元素,而队列空的,不管线程从哪一端试图获取元素,都会被阻塞。

以下是实例化和使用LinkedBlockingDeque的例子:

BlockingDeque<String> deque = new LinkedBlockingDeque<String>();deque.addFirst("1");
deque.addLast("2");String two = deque.takeLast();
String one = deque.takeFirst();

LinkedBlockingDeque的底层数据结构是一个双端队列,该队列使用链表实现,其结构图如下:

源码

LinkedBlockingDequeLinkedBlockingQueue的实现大体上类似,区别在于LinkedBlockingDeque提供的操作更多。并且LinkedBlockingQueue内置两个锁分别用于puttake操作,而LinkedBlockingDeque只使用一个锁控制所有操作。因为队列能够同时在头尾进行puttake操作,所以使用两个锁也需要将两个锁同时加锁才能保证操作的同步性,不如只使用一个锁的性能好。

同步节点相比LinkedBlockingQueue多了一个prev字段。

static final class Node<E> {E item;Node<E> prev;Node<E> next;Node(E x) {item = x;}
}

增加操作

增加操作相比LinkedBlockingQueue只能在队列尾部增加,它能在队列的头尾两端都进行增加操作。

public void addFirst(E e) {// 复用offer方法if (!offerFirst(e))throw new IllegalStateException("Deque full");
}public void addLast(E e) {if (!offerLast(e))throw new IllegalStateException("Deque full");
}public boolean offerFirst(E e) {if (e == null) throw new NullPointerException();// 构造节点Node<E> node = new Node<E>(e);final ReentrantLock lock = this.lock;lock.lock();try {// 插入到队列头部return linkFirst(node);} finally {lock.unlock();}
}private boolean linkFirst(Node<E> node) {// assert lock.isHeldByCurrentThread();// 如果队列已满,返回falseif (count >= capacity)return false;// 获取头节点,将自己的 next字段指向头节点,然后设置自己为头节点Node<E> f = first;node.next = f;first = node;// 如果队列为空,尾节点也指向自己if (last == null)last = node;elsef.prev = node;++count;// 唤醒等待获取元素的线程notEmpty.signal();return true;
}public boolean offerLast(E e) {if (e == null) throw new NullPointerException();Node<E> node = new Node<E>(e);final ReentrantLock lock = this.lock;lock.lock();try {// 插入到队列尾部return linkLast(node);} finally {lock.unlock();}
}private boolean linkLast(Node<E> node) {// assert lock.isHeldByCurrentThread();// 如果队列已满,返回falseif (count >= capacity)return false;// 将自己设置为尾节点Node<E> l = last;node.prev = l;last = node;// 如果队列为空,头节点也指向自己if (first == null)first = node;elsel.next = node;++count;// 唤醒等待获取元素的线程notEmpty.signal();return true;
}public void putFirst(E e) throws InterruptedException {if (e == null) throw new NullPointerException();Node<E> node = new Node<E>(e);final ReentrantLock lock = this.lock;lock.lock();try {// 如果队列已满,等待while (!linkFirst(node))notFull.await();} finally {lock.unlock();}
}public void putLast(E e) throws InterruptedException {if (e == null) throw new NullPointerException();Node<E> node = new Node<E>(e);final ReentrantLock lock = this.lock;lock.lock();try {// 如果队列已满,等待while (!linkLast(node))notFull.await();} finally {lock.unlock();}
}public boolean offerFirst(E e, long timeout, TimeUnit unit)throws InterruptedException {if (e == null) throw new NullPointerException();Node<E> node = new Node<E>(e);// 计算超时时间long nanos = unit.toNanos(timeout);final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {// 如果队列已满,超时等待while (!linkFirst(node)) {if (nanos <= 0L)return false;nanos = notFull.awaitNanos(nanos);}return true;} finally {lock.unlock();}
}public boolean offerLast(E e, long timeout, TimeUnit unit)throws InterruptedException {if (e == null) throw new NullPointerException();Node<E> node = new Node<E>(e);long nanos = unit.toNanos(timeout);final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {while (!linkLast(node)) {if (nanos <= 0L)return false;nanos = notFull.awaitNanos(nanos);}return true;} finally {lock.unlock();}
}

删除操作

public E removeFirst() {// 复用poll操作E x = pollFirst();if (x == null) throw new NoSuchElementException();return x;
}public E removeLast() {E x = pollLast();if (x == null) throw new NoSuchElementException();return x;
}public E pollFirst() {final ReentrantLock lock = this.lock;lock.lock();try {// 获取头节点的值,并删除它return unlinkFirst();} finally {lock.unlock();}
}private E unlinkFirst() {// assert lock.isHeldByCurrentThread();// 如果队列为空,返回nullNode<E> f = first;if (f == null)return null;// 重置头节点Node<E> n = f.next;E item = f.item;f.item = null;f.next = f; // help GCfirst = n;if (n == null)last = null;elsen.prev = null;--count;// 唤醒等待插入的线程notFull.signal();return item;
}public E pollLast() {final ReentrantLock lock = this.lock;lock.lock();try {return unlinkLast();} finally {lock.unlock();}
}private E unlinkLast() {// assert lock.isHeldByCurrentThread();Node<E> l = last;// 队列为空,返回nullif (l == null)return null;// 更新尾节点Node<E> p = l.prev;E item = l.item;l.item = null;l.prev = l; // help GClast = p;if (p == null)first = null;elsep.next = null;--count;notFull.signal();return item;
}public E takeFirst() throws InterruptedException {final ReentrantLock lock = this.lock;lock.lock();try {E x;// 如果队列为空,等待while ( (x = unlinkFirst()) == null)notEmpty.await();return x;} finally {lock.unlock();}
}public E takeLast() throws InterruptedException {final ReentrantLock lock = this.lock;lock.lock();try {E x;// 如果队列为空,等待while ( (x = unlinkLast()) == null)notEmpty.await();return x;} finally {lock.unlock();}
}public E pollFirst(long timeout, TimeUnit unit)throws InterruptedException {long nanos = unit.toNanos(timeout);final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {E x;while ( (x = unlinkFirst()) == null) {if (nanos <= 0L)return null;nanos = notEmpty.awaitNanos(nanos);}return x;} finally {lock.unlock();}
}public E pollLast(long timeout, TimeUnit unit)throws InterruptedException {long nanos = unit.toNanos(timeout);final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {E x;while ( (x = unlinkLast()) == null) {if (nanos <= 0L)return null;nanos = notEmpty.awaitNanos(nanos);}return x;} finally {lock.unlock();}
}

访问操作

public E getFirst() {// 复用peek方法E x = peekFirst();if (x == null) throw new NoSuchElementException();return x;
}public E getLast() {E x = peekLast();if (x == null) throw new NoSuchElementException();return x;
}public E peekFirst() {final ReentrantLock lock = this.lock;lock.lock();try {// 如果队列不为空,返回头元素return (first == null) ? null : first.item;} finally {lock.unlock();}
}public E peekLast() {final ReentrantLock lock = this.lock;lock.lock();try {// 如果队列不为空,返回尾元素return (last == null) ? null : last.item;} finally {lock.unlock();}
}

BlockingQueue

由于BlockingDeque继承自BlockingQueue接口,所以需要实现BlockingQueue中的方法,具体只需要复用前面提到的方法即可。

public boolean add(E e) {addLast(e);return true;
}public boolean offer(E e) {return offerLast(e);
}public void put(E e) throws InterruptedException {putLast(e);
}public boolean offer(E e, long timeout, TimeUnit unit)throws InterruptedException {return offerLast(e, timeout, unit);
}public E remove() {return removeFirst();
}public E poll() {return pollFirst();
}public E take() throws InterruptedException {return takeFirst();
}public E poll(long timeout, TimeUnit unit) throws InterruptedException {return pollFirst(timeout, unit);
}public E element() {return getFirst();
}public E peek() {return peekFirst();
}

核心要点

  • LinkedBlockingDeque 是基于链表的双端阻塞队列,线程安全,元素不允许为 null
  • 内部使用一个双向链表
  • 可以在链表两头同时进行put和take操作,只能使用一个锁
  • 插入线程在执行完操作后如果队列未满会唤醒其他等待插入的线程,同时队列非空还会唤醒等待获取元素的线程;take线程同理。
  • 迭代器与内部的双向链表保持弱一致性,调用 remove(T) 方法删除一个元素后,不会解除其对下一个结点的next引用,否则迭代器将无法工作。
  • 迭代器的forEachRemaining(Consumer<? super E> action)以64个元素为一批进行操作
  • forEach(Consumer<? super E> action),removeIf,removeAll,retainAll都是64个元素为一批进行操作

实战

因为 LinkedBlockingDeque 取出是阻塞的,所以可以做一个 生产-消费 模型

package zyj;import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;public class Product {//指定队列最大值为100BlockingDeque<Apple> deque = new LinkedBlockingDeque(100);//生产,如果队列满了,则抛出 IllegalStateExceptionpublic void produce(Apple apple) {deque.push(apple);}//消费,如果队列为空,则线程阻塞public Apple consume() {try {return deque.take();} catch (InterruptedException e) {e.printStackTrace();}return null;}
}

Java阻塞队列 LinkedBlockingDeque相关推荐

  1. Java阻塞队列ArrayBlockingQueue和LinkedBlockingQueue实现原理分析

    转载自  Java阻塞队列ArrayBlockingQueue和LinkedBlockingQueue实现原理分析 Java中的阻塞队列接口BlockingQueue继承自Queue接口. Block ...

  2. 并发编程5:Java 阻塞队列源码分析(下)

    上一篇 并发编程4:Java 阻塞队列源码分析(上) 我们了解了 ArrayBlockingQueue, LinkedBlockingQueue 和 PriorityBlockingQueue,这篇文 ...

  3. java阻塞队列的使用

    一.阻塞队列的作用 阻塞队列(BlockingQueue),顾名思义,首先它是一个队列,而一个阻塞队列在数据结构中所起的作用大致如图所示: 当阻塞队列是空时,从队列中获取元素的操作将会被阻塞 当阻塞队 ...

  4. Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例

    Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例 本文由 TonySpark 翻译自 Javarevisited.转载请参见文章末尾的要求. Java.util.concurr ...

  5. java阻塞队列小结

    [README] 1,本文介绍了java的7个阻塞队列: 2,阻塞队列的作用 做缓冲作用,如缓冲kafka消息,而不是直接发送给kafka,减少kafka集群的压力: [1]阻塞队列 Blocking ...

  6. java 阻塞队列 LinkedBlockingQueue ArrayBlockingQueue 分析

    BlockingQueue是阻塞队列接口类,该接口继承了Queue接口 BlockingQueue实现类常见的有以下几种. ArrayBlockingQueue:ArrayBlockingQueue ...

  7. java阻塞队列作用_简单理解阻塞队列(BlockingQueue)中的take/put方法以及Condition存在的作用...

    简单理解阻塞队列(BlockingQueue)中的take/put方法以及Condition存在的作用 Condition:可以理解成一把锁的一个钥匙,它既可以解锁(通知放行),又可以加锁(阻塞) n ...

  8. java 阻塞队列介绍

    详细博客:https://www.cnblogs.com/bjxq-cs88/p/9759571.html 阻塞队列(BlockingQueue) 阻塞队列(BlockingQueue)是一个支持两个 ...

  9. java 阻塞队列 BQ_阻塞队列 BlockingQueue的使用(二)

    原 阻塞队列 BlockingQueue的使用(二) BlockingQueue 的核心方法:方法类型抛出异常特殊值阻塞超时 插入add(e)offer(e)put(e)offer(e,time,un ...

最新文章

  1. 1024,不讲技术,来一套程序员续命操~
  2. C语言数组栈怎么实现删除,C语言静态数组实现栈操作
  3. python管理包管理工具pip和conda使用,及使用pip和conda创建虚拟环境
  4. 4月13日学习笔记——jQuery动画
  5. 2021-01-22 Python TimedRotatingFileHandler 修改suffix后无法自动删除文件
  6. GitLab怎样实现新建仓库并允许开发者推送代码实现协同开发
  7. AAAI 2022 | 北大 阿里达摩院:基于对比学习的预训练语言模型剪枝压缩
  8. 使用DPM 2010备份还原Exchange2010单个邮箱
  9. 嵌入式开发硬件知识札记
  10. HashMap HashTable ConcurrentHashMap
  11. 如何解决NLP分类任务的11个关键问题:类别不平衡低耗时计算小样本鲁棒性测试检验长文本分类 JayLou娄杰
  12. safari使用canvas引入域外的图片
  13. html漂亮的表格模板+背景_咨询amp;金融主题响应式网站着陆页模板
  14. Android Html.fromhtml
  15. endnote导入参考文献及国标(Chinese standard)
  16. 最新微软产品MAK激活密钥
  17. 转载---SQL Server XML基础学习之7--XML modify() 方法对 XML 数据中插入、更新或删除...
  18. 谈 Scratch 版“植物大战僵尸”
  19. 计算机毕业设计:基于微信小程序的校园求职系统
  20. Ubuntu如何安装Python

热门文章

  1. html传输php连接mysql数据库_解析HTML、JS与PHP之间的数据传输
  2. java线程死亡_java – 如何暂停main()直到所有其他线程死亡?
  3. 五十六、从高中碾转相除法、更相减损术算法谈起
  4. 七十六、Python | Leetcode二分查找和分治算法系列
  5. 三、数据分析前,打下数据处理基础(下)
  6. 微信小程序学习笔记(四)
  7. 阿里云机器学习PAI构建AI集团军作战,联手Intel在AI软硬件领域发力
  8. 视频预测领域有哪些最新研究进展?不妨看看这几篇顶会论文
  9. CVPR 2019 | 小样本域适应的目标检测
  10. 目标检测基本概念理解之IoU(交并比)以及Python代码实现