ArrayBlockingQueue源码解析(2)
此文已由作者赵计刚授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
3.3、public void put(E e) throws InterruptedException
原理:
在队尾插入一个元素,如果队列满了,一直阻塞,直到数组不满了或者线程被中断
使用方法:
try {
abq.put("hello1");
} catch (InterruptedException e) {
e.printStackTrace();
}
源代码:
/**
* 在队尾插入一个元素
* 如果队列满了,一直阻塞,直到数组不满了或者线程被中断
*/
public void put(E e) throws InterruptedException {
if (e == null)
throw new NullPointerException();
final E[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
try {
while (count == items.length)//队列满了,一直阻塞在这里
/*
* 一直等待条件notFull,即被其他线程唤醒
* (唤醒其实就是,有线程将一个元素出队了,然后调用notFull.signal()唤醒其他等待这个条件的线程,同时队列也不慢了)
*/
notFull.await();
} catch (InterruptedException ie) {//如果被中断
notFull.signal(); // 唤醒其他等待该条件(notFull,即入队)的线程
throw ie;
}
insert(e);
} finally {
lock.unlock();
}
}
4、出队
4.1、public E poll()
原理:
如果没有元素,直接返回null;如果有元素,将队头元素置null,但是要注意队头是随时变化的,并非一直是items[0]。
使用方法:
abq.poll();
源代码:
/**
* 出队
*/
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == 0)//如果没有元素,直接返回null,而非抛出异常
return null;
E x = extract();
return x;
} finally {
lock.unlock();
}
}
/**
* 出队
*/
private E extract() {
final E[] items = this.items;
E x = items[takeIndex];//获取出队元素
items[takeIndex] = null;//将出队元素位置置空
/*
* 第一次出队的元素takeIndex==0,第二次出队的元素takeIndex==1
* (注意:这里出队之后,并没有将后面的数组元素向前移)
*/
takeIndex = inc(takeIndex);
--count;//数组元素个数-1
notFull.signal();//数组已经不满了,唤醒其他等待notFull条件的线程
return x;//返回出队的元素
}
4.2、public E poll(long timeout, TimeUnit unit) throws InterruptedException
原理:
从对头删除一个元素,如果数组不空,出队;如果数组已空且已经超时,返回null;如果数组已空且时间未超时,则进入等待,直到出现以下三种情况:
被唤醒
等待时间超时
当前线程被中断
使用方法:
try {
abq.poll(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
源代码:
/**
* 从对头删除一个元素,
* 如果数组不空,出队;
* 如果数组已空,判断时间是否超时,如果已经超时,返回null
* 如果数组已空且时间未超时,则进入等待,直到出现以下三种情况:
* 1、被唤醒
* 2、等待时间超时
* 3、当前线程被中断
*/
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);//将时间转换为纳秒
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
if (count != 0) {//数组不空
E x = extract();//出队
return x;
}
if (nanos <= 0)//时间超时
return null;
try {
/*
* 进行等待:
* 在这个过程中可能发生三件事:
* 1、被唤醒-->继续当前这个for(;;)循环
* 2、超时-->继续当前这个for(;;)循环
* 3、被中断-->之后直接执行catch部分的代码
*/
nanos = notEmpty.awaitNanos(nanos);
} catch (InterruptedException ie) {
notEmpty.signal(); // propagate to non-interrupted thread
throw ie;
} }
} finally {
lock.unlock();
}
}
4.3、public E take() throws InterruptedException
原理:
将队头元素出队,如果队列空了,一直阻塞,直到数组不为空或者线程被中断
使用方法:
try {
abq.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
源代码:
/**
* 将队头元素出队
* 如果队列空了,一直阻塞,直到数组不为空或者线程被中断
*/
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
try {
while (count == 0)//如果数组为空,一直阻塞在这里
/*
* 一直等待条件notEmpty,即被其他线程唤醒
* (唤醒其实就是,有线程将一个元素入队了,然后调用notEmpty.signal()唤醒其他等待这个条件的线程,同时队列也不空了)
*/
notEmpty.await();
} catch (InterruptedException ie) {
notEmpty.signal(); // propagate to non-interrupted thread
throw ie;
}
E x = extract();
return x;
} finally {
lock.unlock();
}
}
总结:
1、具体入队与出队的原理图:这里只说一种情况,见下图,途中深色部分表示已有元素,浅色部分没有元素。
上面这种情况是怎么形成的呢?当队列满了,这时候,队头元素为items[0]出队了,就形成上边的这种情况。
假设现在又要出队了,则现在的队头元素是items[1],出队后就形成下面的情形。
出队后,对头元素就是items[2]了,假设现在有一个元素将要入队,根据inc方法,我们可以得知,他要插入到items[0]去,入队了形成下图:
以上就是整个入队出队的流程,inc方法上边已经给出,这里再贴一遍:
/**
* i+1,数组下标+1
* 注意:这里这样写的原因。
*/
final int inc(int i) {
return (++i == items.length) ? 0 : i;
}
2、三种入队对比:
offer(E e):如果队列没满,立即返回true; 如果队列满了,立即返回false-->不阻塞
put(E e):如果队列满了,一直阻塞,直到数组不满了或者线程被中断-->阻塞
offer(E e, long timeout, TimeUnit unit):在队尾插入一个元素,,如果数组已满,则进入等待,直到出现以下三种情况:-->阻塞
被唤醒
等待时间超时
当前线程被中断
3、三种出对对比:
poll():如果没有元素,直接返回null;如果有元素,出队
take():如果队列空了,一直阻塞,直到数组不为空或者线程被中断-->阻塞
poll(long timeout, TimeUnit unit):如果数组不空,出队;如果数组已空且已经超时,返回null;如果数组已空且时间未超时,则进入等待,直到出现以下三种情况:
被唤醒
等待时间超时
当前线程被中断
免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 深入解析SQLServer高可用镜像实现原理
ArrayBlockingQueue源码解析(2)的更多相关文章
- ArrayBlockingQueue源码解析(1)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 注意:在阅读本文之前或在阅读的过程中,需要用到ReentrantLock,内容见<第五章 Reentr ...
- 第八章 ArrayBlockingQueue源码解析
注意:在阅读本文之前或在阅读的过程中,需要用到ReentrantLock,内容见<第五章 ReentrantLock源码解析1--获得非公平锁与公平锁lock()><第六章 Reen ...
- Java并发包源码学习系列:阻塞队列实现之ArrayBlockingQueue源码解析
目录 ArrayBlockingQueue概述 类图结构及重要字段 构造器 出队和入队操作 入队enqueue 出队dequeue 阻塞式操作 E take() 阻塞式获取 void put(E e) ...
- Java源码解析——集合框架(二)——ArrayBlockingQueue
ArrayBlockingQueue源码解析 ArrayBlockingQueue是一个阻塞式的队列,继承自AbstractBlockingQueue,间接的实现了Queue接口和Collection ...
- 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 ...
随机推荐
- windows中执行celery beat任务
由于最新的celery4.2不支持windows系统,因此按照网上的建议安装了3.1.25版.按照官网的说明使用 app.conf.beat_schedule = { 'add-every-30-se ...
- 【C++】c++中栈 队列 的应用
C++中提供了STL模板statck 在使用的时候更为方便 除了一般的队列外 还有STL更有双向队列可以使用 #include<deque> 声明:deque <type > ...
- Tarjan 割点,桥
/* ggg ggg ggggggg ggggggg ggggggggggggggggggg ggggggggggggggg ggggggggggg ggggggg ggg g */ /* gyt L ...
- 20175316盛茂淞-Java第1周学习总结
20175316盛茂淞 2018-2019-2 <Java程序设计>第1周学习总结 教材学习内容总结 Java入门 1.Java简介(地位,特点) 2.安装JDK,设置系统环境 3.编译J ...
- 代理设计模式 (静态代理设计模式)+ 动态代理(JDK和Cglib)
一.代理设计模式 1.设计模式:前人总结一套解决特定问题的代码 2.代理设计模式优点: 2.1 保护真实对象 2.2 让真实对象职责更明确 2.3 扩展 3.代理设计模式 3.1 真实对象(老总) 3 ...
- De Bruijn序列
最近文章中经常出现及De Bruijin 这个关键字,网上搜索了一下,记录下来. De Bruijn序列 (德布鲁因序列) 问题:能否构造一个长度为2的n次方的二进制环状串,使得二进制环状串中总共2的 ...
- 2018.12.14 codeforces 932E. Team Work(组合数学)
传送门 组合数学套路题. 要求ans=∑i=0nCni∗ik,n≤1e9,k≤5000ans=\sum_{i=0}^n C_n^i*i^k,n\le 1e9,k\le 5000ans=∑i=0nCn ...
- char与CString相互转换
Char -> CStringchar ch[] = "Hello";CString str;str.Format("%s",ch);CString -& ...
- JavaScript 模拟键盘事件和鼠标事件(比如模拟按下回车等)
http://blog.csdn.net/lovelyelfpop/article/details/52471878# 封装好的function大概就是这样: function fireKeyEven ...
- IntelliJ IDEA 2017版 spring-boot搭建拦截器
1.建立一个springboot-web项目 https://www.cnblogs.com/liuyangfirst/p/8298588.html 2.加入过滤接口 public class Log ...