LinkedBlockingQueue源码解析(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();
int c = -1;
final ReentrantLock putLock = this.putLock;//入队锁
final AtomicInteger count = this.count;//当前队列中的元素个数
putLock.lockInterruptibly();//加锁
try {
while (count.get() == capacity) {//如果队列满了
/*
* 加入notFull等待队列,直到队列元素不满了,
* 被其他线程使用notFull.signal()唤醒
*/
notFull.await();
}
enqueue(e);//入队
c = count.getAndIncrement();//入队数量+1
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
4、出队
4.1、public E poll()
原理:
如果没有元素,直接返回null;如果有元素,出队
使用方法:
abq.poll();
源代码:
/**
* 出队:
* 1、如果没有元素,直接返回null
* 2、如果有元素,出队
*/
public E poll() {
final AtomicInteger count = this.count;// 获取元素数量
if (count.get() == 0)// 没有元素
return null;
E x = null;
int c = -1;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();// 获取出队锁
try {
if (count.get() > 0) {// 有元素
x = dequeue();// 出队
// 元素个数-1(注意:该方法是一个无限循环,直到减1成功为止,且返回旧值)
c = count.getAndDecrement();
if (c > 1)// 还有元素(如果旧值c==1的话,那么通过上边的操作之后,队列就空了)
notEmpty.signal();// 唤醒等待在notEmpty队列中的其中一条线程
}
} finally {
takeLock.unlock();// 释放出队锁
}
if (c == capacity)// c == capacity是怎么发生的?如果队列是一个满队列,注意:上边的c返回的是旧值
signalNotFull();
return x;
}
/**
* 从队列头部移除一个节点
*/
private E dequeue() {
Node<E> h = head;//获取头节点:x==null
Node<E> first = h.next;//将头节点的下一个节点赋值给first
h.next = h; // 将当前将要出队的节点置null(为了使其做head节点做准备)
head = first;//将当前将要出队的节点作为了头节点
E x = first.item;//获取出队节点的值
first.item = null;//将出队节点的值置空
return x;
}
private void signalNotFull() {
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
notFull.signal();
} finally {
putLock.unlock();
}
}
注意:出队逻辑如果不懂,查看最后总结部分的图
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 {
E x = null;
int c = -1;
long nanos = unit.toNanos(timeout);
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {//如果队列没有元素
if (nanos <= 0)//已经超时
return null;
/*
* 进行等待:
* 在这个过程中可能发生三件事:
* 1、被唤醒-->继续当前这个while循环
* 2、超时-->继续当前这个while循环
* 3、被中断-->抛出异常
*/
nanos = notEmpty.awaitNanos(nanos);
}
x = dequeue();//出队
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 基于开源,强于开源,轻舟微服务解决方案深度解读
【推荐】 云计算交互设计师的正确出装姿势
LinkedBlockingQueue源码解析(2)的更多相关文章
- LinkedBlockingQueue源码解析
上一篇博客,我们介绍了ArrayBlockQueue,知道了它是基于数组实现的有界阻塞队列,既然有基于数组实现的,那么一定有基于链表实现的队列了,没错,当然有,这就是我们今天的主角:LinkedBlo ...
- LinkedBlockingQueue源码解析(3)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 4.3.public E take() throws InterruptedException 原理: 将队 ...
- 第九章 LinkedBlockingQueue源码解析
1.对于LinkedBlockingQueue需要掌握以下几点 创建 入队(添加元素) 出队(删除元素) 2.创建 Node节点内部类与LinkedBlockingQueue的一些属性 static ...
- Java并发包源码学习系列:阻塞队列实现之LinkedBlockingQueue源码解析
目录 LinkedBlockingQueue概述 类图结构及重要字段 构造器 出队和入队操作 入队enqueue 出队dequeue 阻塞式操作 E take() 阻塞式获取 void put(E e ...
- LinkedBlockingQueue源码解析(1)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 1.对于LinkedBlockingQueue需要掌握以下几点 创建 入队(添加元素) 出队(删除元素) 2 ...
- 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 ...
随机推荐
- centos6.6 下 安装 nginx
1.安装nginx需要pcre的依赖,请安装好pcre.假设安装目录如下: /usr/local/pcre-8.38 源码目录如下: /usr/src/pcre-8.38 2.下载nginx安装压缩包 ...
- mysql优化概述2
一.索引的概念 利用关键字,就是记录的部分数据(某个字段,某些字段,某个字段的一部份),建立与记录位置的对应关系,就是索引.索引的关键字一定是排序的. 二.索引的类型 mysql支持四种索引: 1.主 ...
- NPOI导入导出Excel数据
代码: using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System; usi ...
- [BAT]cmd命令之 cd /d %~dp0
cd /d %~dp0是什么意思啊?批处理文件中的一条语句意思是 更改当前目录为批处理本身的目录 有些晕吧?不急,我举例 比如你有个批处理a.bat在D:\qq文件夹下 a.bat内容为 cd /d ...
- 使用nmon来按频率采集数据
# nmon -s1 -c60 -f -m /home/nmon # ll /home/nmon/ total 15220 -rw-r--r-- 1 root root 23923 Oct 14 ...
- maven 编译的时候总是报一些奇怪的错误 比如 surefire-boot 2.10 .jar 可是私服里查看本来就没有这个高的版本。
或者私服总是 报 read time out , 或者 io 错误, 或者 gzip 解压错误,或者总是尝试下载一些高版本的jar , 而这些jar 可能是不存在的 .. 尝试 重新下载 apac ...
- 转载hibernate 的3种 状态 。。
转自 http://huangtut.iteye.com/blog/261520 对我有帮助,所以收藏了 Hibernate三种状态的区分,以及save,update,saveOrUpdate,m ...
- Android 控制ScrollView滚动到底部或顶部
在开发中,我们经常需要更新列表,并将列表拉倒最底部,比如发表微博,聊天界面等等, 这里有两种办法,第一种,使用scrollTo(): public static void scrollToBottom ...
- Winform窗体控件级权限处理
公共类: static class PowerHelper { /// <summary> /// 设置form上的组件的权限 /// ...
- this.closest()在IE中报错的原因及解决办法
closest()定义在jquery中,不能在原生的js中使用 解决方法:将this.closest()换成$(this).closest()即可