Java并发包源码学习系列:阻塞队列实现之LinkedBlockingDeque源码解析
系列传送门:
- Java并发包源码学习系列:AbstractQueuedSynchronizer
- Java并发包源码学习系列:CLH同步队列及同步资源获取与释放
- Java并发包源码学习系列:AQS共享式与独占式获取与释放资源的区别
- Java并发包源码学习系列:ReentrantLock可重入独占锁详解
- Java并发包源码学习系列:ReentrantReadWriteLock读写锁解析
- Java并发包源码学习系列:详解Condition条件队列、signal和await
- Java并发包源码学习系列:挂起与唤醒线程LockSupport工具类
- Java并发包源码学习系列:JDK1.8的ConcurrentHashMap源码解析
- Java并发包源码学习系列:阻塞队列BlockingQueue及实现原理分析
- Java并发包源码学习系列:阻塞队列实现之ArrayBlockingQueue源码解析
- Java并发包源码学习系列:阻塞队列实现之LinkedBlockingQueue源码解析
- Java并发包源码学习系列:阻塞队列实现之PriorityBlockingQueue源码解析
- Java并发包源码学习系列:阻塞队列实现之DelayQueue源码解析
- Java并发包源码学习系列:阻塞队列实现之SynchronousQueue源码解析
- Java并发包源码学习系列:阻塞队列实现之LinkedTransferQueue源码解析
LinkedBlockingDeque概述
LinkedBlockingDeque是由链表构成的界限可选的双端阻塞队列,支持O(1)的时间复杂度从两端插入和移除元素,如不指定边界,则为Integer.MAX_VALUE
。
由一个ReentrantLock保证同步,使用conditions来实现等待通知。
类图结构及重要字段
public class LinkedBlockingDeque<E>
extends AbstractQueue<E>
implements BlockingDeque<E>, java.io.Serializable {
private static final long serialVersionUID = -387911632671998426L;
/** 双向链表节点 */
static final class Node<E> {
E item;
Node<E> prev;
Node<E> next;
Node(E x) {
item = x;
}
}
/**
* 指向第一个节点
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* 指向最后一个节点
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
/** 节点数量 */
private transient int count;
/** 队列容量 */
private final int capacity;
/** 保证同步 */
final ReentrantLock lock = new ReentrantLock();
/** take操作发生的条件 */
private final Condition notEmpty = lock.newCondition();
/** put操作发生的条件 */
private final Condition notFull = lock.newCondition();
}
linkFirst
尝试将节点加入到first之前,更新first,如果插入之后超出容量,返回false。
private boolean linkFirst(Node<E> node) {
// assert lock.isHeldByCurrentThread();
if (count >= capacity)
return false;
Node<E> f = first;
node.next = f;
first = node;
if (last == null)
last = node;
else
f.prev = node;
++count;
notEmpty.signal();
return true;
}
linkLast
在last节点后加入节点node,更新last。如果插入之后超出容量,返回false。
private boolean linkLast(Node<E> node) {
// assert lock.isHeldByCurrentThread();
if (count >= capacity)
return false;
Node<E> l = last;
node.prev = l;
last = node;
if (first == null)
first = node;
else
l.next = node;
++count;
notEmpty.signal();// 满足notEmpty条件
return true;
}
unlinkFirst
移除first节点,并返回其item值,如果队列为空,则返回full。
private E unlinkFirst() {
// assert lock.isHeldByCurrentThread();
Node<E> f = first;
if (f == null)
return null;
Node<E> n = f.next;
E item = f.item;
f.item = null;
f.next = f; // help GC
first = n;
if (n == null)
last = null;
else
n.prev = null;
--count;
notFull.signal();// 满足notFull条件
return item;
}
unlinkLast
移除last节点,并返回其item值,如果队列为空,则返回full。
private E unlinkLast() {
// assert lock.isHeldByCurrentThread();
Node<E> l = last;
if (l == null)
return null;
Node<E> p = l.prev;
E item = l.item;
l.item = null;
l.prev = l; // help GC
last = p;
if (p == null)
first = null;
else
p.next = null;
--count;
notFull.signal(); // 满足notFull条件
return item;
}
unlink
移除任意一个节点,注意这里并没有操作x本身的连接,因为它可能仍被iterator使用着。
void unlink(Node<E> x) {
// assert lock.isHeldByCurrentThread();
Node<E> p = x.prev;
Node<E> n = x.next;
// 移除的是first
if (p == null) {
unlinkFirst();
// 移除的是last
} else if (n == null) {
unlinkLast();
} else {
// 移除的是中间节点
p.next = n;
n.prev = p;
x.item = null;
// Don't mess with x's links. They may still be in use by
// an iterator.
// 这里x的prev和next指针都没有改变,因为他们可能在被iterator使用
--count;
notFull.signal();
}
}
总结
LinkedBlockingDeque是由链表构成的界限可选的双端阻塞队列,支持O(1)的时间复杂度从两端插入和移除元素,如不指定边界,则为Integer.MAX_VALUE
。
由一个ReentrantLock保证同步,使用conditions来实现等待通知。
上面介绍的所有操作基本上就是核心方法啦,诸如putFirst、putLast、takeFirst、takeLast等方法都会调用上面的核心方法,而且实现上面也是比较简单的,就是双端链表的基本操作,不懂的可以画画图帮助理解哈。
参考阅读
《Java并发编程的艺术》
《Java并发编程之美》
Java并发包源码学习系列:阻塞队列实现之LinkedBlockingDeque源码解析的更多相关文章
- Java并发包源码学习系列:JDK1.8的ConcurrentHashMap源码解析
目录 为什么要使用ConcurrentHashMap? ConcurrentHashMap的结构特点 Java8之前 Java8之后 基本常量 重要成员变量 构造方法 tableSizeFor put ...
- Java并发包源码学习系列:阻塞队列BlockingQueue及实现原理分析
目录 本篇要点 什么是阻塞队列 阻塞队列提供的方法 阻塞队列的七种实现 TransferQueue和BlockingQueue的区别 1.ArrayBlockingQueue 2.LinkedBloc ...
- Java并发包源码学习系列:阻塞队列实现之ArrayBlockingQueue源码解析
目录 ArrayBlockingQueue概述 类图结构及重要字段 构造器 出队和入队操作 入队enqueue 出队dequeue 阻塞式操作 E take() 阻塞式获取 void put(E e) ...
- Java并发包源码学习系列:阻塞队列实现之LinkedBlockingQueue源码解析
目录 LinkedBlockingQueue概述 类图结构及重要字段 构造器 出队和入队操作 入队enqueue 出队dequeue 阻塞式操作 E take() 阻塞式获取 void put(E e ...
- Java并发包源码学习系列:阻塞队列实现之PriorityBlockingQueue源码解析
目录 PriorityBlockingQueue概述 类图结构及重要字段 什么是二叉堆 堆的基本操作 向上调整void up(int u) 向下调整void down(int u) 构造器 扩容方法t ...
- Java并发包源码学习系列:阻塞队列实现之DelayQueue源码解析
目录 DelayQueue概述 类图及重要字段 Delayed接口 Delayed元素案例 构造器 put take first = null 有什么用 总结 参考阅读 系列传送门: Java并发包源 ...
- Java并发包源码学习系列:阻塞队列实现之SynchronousQueue源码解析
目录 SynchronousQueue概述 使用案例 类图结构 put与take方法 void put(E e) E take() Transfer 公平模式TransferQueue QNode t ...
- Java并发包源码学习系列:阻塞队列实现之LinkedTransferQueue源码解析
目录 LinkedTransferQueue概述 TransferQueue 类图结构及重要字段 Node节点 前置:xfer方法的定义 队列操作三大类 插入元素put.add.offer 获取元素t ...
- Java并发包源码学习系列:线程池ThreadPoolExecutor源码解析
目录 ThreadPoolExecutor概述 线程池解决的优点 线程池处理流程 创建线程池 重要常量及字段 线程池的五种状态及转换 ThreadPoolExecutor构造参数及参数意义 Work类 ...
随机推荐
- MySQL [ERROR] Table 'mysql.user' doesn't exist
问题描述: 在安装MYsql时,/etc/init.d/mysqld start时报错: [root@master data]# /etc/init.d/mysqld start Starting M ...
- 神经网络中的降维和升维方法 (tensorflow & pytorch)
大名鼎鼎的UNet和我们经常看到的编解码器模型,他们的模型都是先将数据下采样,也称为特征提取,然后再将下采样后的特征恢复回原来的维度.这个特征提取的过程我们称为"下采样",这个恢复 ...
- Linux LVM Logical Volume Management 逻辑卷的管理
博主是一个数据库DBA,但是一般来说,是不做linux服务器LVM 逻辑卷的创建.扩容和减容操作的,基本上有系统管理员操作,一是各司其职,专业的事专业的人做,二是做多了你的责任也多了,哈哈! 但是li ...
- Docker-ce运用一:创建虚拟机
1.从远程仓库查看所需镜像 [root@localhost docker]# docker search centos8 NAME DE ...
- (解决)easypoi模板导出多个excel文件并压缩
目录 easypoi版本--3.1.0 实现代码 后语 easypoi版本--3.1.0 实现代码 public void export(HttpServletResponse response, H ...
- 【Flutter】可滚动组件之SingleChildScrollView
前言 SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子组件. 接口描述 const SingleChildScrollView({ Key ke ...
- ajax跨域访问http服务--jsonp
在前面一篇文章<Spring Cloud 前后端分离后引起的跨域访问解决方案>里我们提到使用ajax跨域请求其他应用的http服务,使用的是后台增加注解@CrossOrigin或者增加Co ...
- 【MySQL】使用MySQL(连接、选择数据库、显示数据库和表信息)
第3章 使用MySQL 文章目录 第3章 使用MySQL 连接 选择数据库 了解数据库和表 小结 简单记录 - MySQL必知必会 - [英]Ben Forta 将学习如何连接和登录到MySQL,如何 ...
- Java高并发与多线程(二)-----线程的实现方式
今天,我们开始Java高并发与多线程的第二篇,线程的实现方式. 通常来讲,线程有三种基础实现方式,一种是继承Thread类,一种是实现Runnable接口,还有一种是实现Callable接口,当然,如 ...
- 【Docker】/usr/bin/docker-current: Cannot connect to the Docker daemon at unix
------------------------------------------------------------------------------------------------- | ...