BlockingQueue的基本原理
1. 前言
BlockingQueue即阻塞队列,它算是一种将ReentrantLock用得非常精彩的一种表现,依据它的基本原理,我们可以实现Web中的长连接聊天功能,当然其最常用的还是用于实现生产者与消费者模式,大致如下图所示:

在Java中,BlockingQueue是一个接口,它的实现类有ArrayBlockingQueue、DelayQueue、 LinkedBlockingDeque、LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue等,它们的区别主要体现在存储结构上或对元素操作上的不同,但是对于take与put操作的原理,却是类似的。下面的源码以ArrayBlockingQueue为例。
2. 分析
BlockingQueue内部有一个ReentrantLock,其生成了两个Condition,在ArrayBlockingQueue的属性声明中可以看见:
/** Main lock guarding all access */
final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull; ... public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
而如果能把notEmpty、notFull、put线程、take线程拟人的话,那么我想put与take操作可能会是下面这种流程:
put(e)

take()

其中ArrayBlockingQueue.put(E e)源码如下(其中中文注释为自定义注释,下同):
/**
* Inserts the specified element at the tail of this queue, waiting
* for space to become available if the queue is full.
*
* @throws InterruptedException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await(); // 如果队列已满,则等待
insert(e);
} finally {
lock.unlock();
}
} /**
* Inserts element at current put position, advances, and signals.
* Call only when holding lock.
*/
private void insert(E x) {
items[putIndex] = x;
putIndex = inc(putIndex);
++count;
notEmpty.signal(); // 有新的元素被插入,通知等待中的取走元素线程
}
ArrayBlockingQueue.take()源码如下:
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await(); // 如果队列为空,则等待
return extract();
} finally {
lock.unlock();
}
}
/**
* Extracts element at current take position, advances, and signals.
* Call only when holding lock.
*/
private E extract() {
final Object[] items = this.items;
E x = this.<E>cast(items[takeIndex]);
items[takeIndex] = null;
takeIndex = inc(takeIndex);
--count;
notFull.signal(); // 有新的元素被取走,通知等待中的插入元素线程
return x;
}
可以看见,put(E)与take()是同步的,在put操作中,当队列满了,会阻塞put操作,直到队列中有空闲的位置。而在take操作中,当队列为空时,会阻塞take操作,直到队列中有新的元素。
而这里使用两个Condition,则可以避免调用signal()时,会唤醒相同的put或take操作。
BlockingQueue的基本原理的更多相关文章
- Disruptor学习笔记(一):基本原理和概念
一.Disruptor基本原理 在多线程开发中,我们常常遇到这样一种场景:一些线程接受用户请求,另外一些线程处理这些请求.比如日志处理中的日志输入和告警.这种典型的生产者消费者场景十分常见,而生产者消 ...
- 【转】不怕难之BlockingQueue及其实现
1. 前言 BlockingQueue即阻塞队列,它是基于ReentrantLock,依据它的基本原理,我们可以实现Web中的长连接聊天功能,当然其最常用的还是用于实现生产者与消费者模式,大致如下图所 ...
- 加深一下BlockingQueue的认识
认识BlockingQueue BlockingQueue是一种可以阻塞线程的队列,java中对这种队列提供了方法抽象,BlockingQueue则是抽象的接口. add:添加元素到队列里,添加成功返 ...
- Ognl表达式基本原理和使用方法
Ognl表达式基本原理和使用方法 1.Ognl表达式语言 1.1.概述 OGNL表达式 OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,他是一个 ...
- Android自定义控件之基本原理
前言: 在日常的Android开发中会经常和控件打交道,有时Android提供的控件未必能满足业务的需求,这个时候就需要我们实现自定义一些控件,今天先大致了解一下自定义控件的要求和实现的基本原理. 自 ...
- HMM基本原理及其实现(隐马尔科夫模型)
HMM(隐马尔科夫模型)基本原理及其实现 HMM基本原理 Markov链:如果一个过程的“将来”仅依赖“现在”而不依赖“过去”,则此过程具有马尔可夫性,或称此过程为马尔可夫过程.马尔可夫链是时间和状态 ...
- 动态令牌-(OTP,HOTP,TOTP)-基本原理
名词解释和基本介绍 OTP 是 One-Time Password的简写,表示一次性密码. HOTP 是HMAC-based One-Time Password的简写,表示基于HMAC算法加密的一次性 ...
- ZooKeeper基本原理
ZooKeeper简介 ZooKeeper是一个开放源码的分布式应用程序协调服务,它包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等. ZooKeeper设计目的 1. ...
- GBDT的基本原理
这里以二元分类为例子,给出最基本原理的解释 GBDT 是多棵树的输出预测值的累加 GBDT的树都是 回归树 而不是分类树 分类树 分裂的时候选取使得误差下降最多的分裂 计算的技巧 最终分裂收益按照下面 ...
随机推荐
- elasticsearch7.x配置文件
前言: 以下配置文件基于elasticsearch-7.13.4版本,当然也适用于其它7.x版本 集群环境: 部署3个节点的集群,各个节点不做角色区分,既是master,也是data,在性能 上这种方 ...
- 7-7 后缀式求值 (25分)的python实现
exp=input().split() ls=list() def Cal(a,b,i): if i=="+": return a+b elif i=="-": ...
- find 删除日志文件
find 命令删除日志文件 find ./my_dir -mtime +10 -type f -delete EXPLANATIONS ./my_dir your directory (replace ...
- lombok标签之@Data @AllArgsConstructor @@NoArgsConstructor -如何去除get,set方法。@Data注解和如何使用,lombok
在代码中我们可以只加上标签@Data 而不用get,set方法: val : 和 scala 中 val 同名, 可以在运行时确定类型; @NonNull : 注解在参数上, 如果该类参数为 null ...
- Python编程环境设置
第1节.Python编程环境设置 一.sublime相关 1.sublime REPL插件安装 (1)安装 先打开插件安装面板:ctrl+shift+P 输入install ,选择Package Co ...
- 论文解读(node2vec)《node2vec Scalable Feature Learning for Networks》
论文题目:<node2vec Scalable Feature Learning for Network>发表时间: KDD 2016 论文作者: Aditya Grover;Adit ...
- processon刷文件的骚操作
https://github.com/ilikly/ProcessOnRegister用法自己看说明哈,群友亲测可用,而且也给别人用了...缺点是每轮都需要手动操作一下,并且需要俩微信号
- 关于postman的接口登录验证问题
1.shiro的接口登录问题 碰到需要接口登录验证的:访问项目接口地址login,找到cookie将Cookie数据放入postman的headers 中. 2.碰到 security的项目.首先把相 ...
- 洛谷 P3994 高速公路(斜率优化)
题目链接 题意:给出一棵树,\(1\) 号点为根,边上有边权. 每个点有两个参数 \(p_i,q_i\) 如果你想从 \(i\) 号点到与其距离为 \(d\) 的 \(j\) 号点,那么你需花费 \( ...
- Atcoder Regular Contst 084 D - XorShift(bitset)
洛谷题面传送门 & Atcoder 题面传送门 没错,这就是 Small Multiple 那场的 F,显然这种思维题对我来说都是不可做题/cg/cg/cg 首先如果我们把每个二进制数看作一个 ...