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的树都是 回归树 而不是分类树 分类树 分裂的时候选取使得误差下降最多的分裂 计算的技巧 最终分裂收益按照下面 ...
随机推荐
- 常见yaml写法-job
apiVersion: batch/v1 kind: Job metadata: name: job-demo spec: template: metadata: name: job-demo spe ...
- 尖端之作看逐浪-Zoomla!逐浪CMS python版发布
免费下载:https://www.z01.com/down/3723.shtml Python是跻身于当代IT世界最流行和代码最高效的编程语言之一. 带着对技术的卓越追求.对客户的承诺.对品质的极致追 ...
- Django 小实例S1 简易学生选课管理系统 1 项目流程梳理与数据库设计
Django 小实例S1 简易学生选课管理系统 第1章--项目流程梳理与数据库设计 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 1 项目流程梳理 ...
- [bzoj1432]Function
对于这n个函数,构成了$n(n-1)/2$个交点,对交点离散后,相邻两个交点间函数的编号构成了一个排列,而每一个排列第i个数所构成的段数就是第i层的段数不妨设初始在-oo处这个排列是1,2,--,n, ...
- Assassin暗杀者-自用短小精悍的webshell管理工具分享
Assassin Assassin是一款精简的基于命令行的webshell管理工具,它有着多种payload发送方式和编码方式,以及精简的payload代码,使得它成为隐蔽的暗杀者,难以被很好的防御. ...
- mybatis避免sql的like注入
<select id="NotInByEvalQuestion" resultType="com.rm.eval.entity.EvalQnQuestion&quo ...
- html+css第六篇-定位
relative相对定位/定位偏移量 position:relative; 相对定位 a.不影响元素本身的特性: b.不使元素脱离文档流: c.如果没有定位偏移量,对元素本身没有任何影响: 定位元素位 ...
- LOJ #2769 -「ROI 2017 Day 1」前往大都会(单调栈维护斜率优化)
LOJ 题面传送门 orz 斜率优化-- 模拟赛时被这题送走了,所以来写篇题解( 首先这个最短路的求法是 trivial 的,直接一遍 dijkstra 即可( 重点在于怎样求第二问.注意到这个第二问 ...
- LOJ #6207 - 米缇(杜教筛+拉格朗日插值)
LOJ 题面传送门 首先将 \(\sigma_k(ij)\) 展开: \[\sigma_k(ij)=\sum\limits_{x\mid i}\sum\limits_{y\mid j}[x\perp ...
- 洛谷 P3239 [HNOI2015]亚瑟王(期望+dp)
题面传送门 感觉是道挺好的题,可惜当时没写题解来着的? 根据期望的线性公式,我们求出每个卡牌被发动的概率 \(q_i\),然后 \[ans=\sum\limits_{i=1}^np_id_i \] 于 ...