LinkedBlockingQueue源码解析(1)
此文已由作者赵计刚授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
1、对于LinkedBlockingQueue需要掌握以下几点
创建
入队(添加元素)
出队(删除元素)
2、创建
Node节点内部类与LinkedBlockingQueue的一些属性
static class Node<E> {
E item;//节点封装的数据
/**
* One of:
* - the real successor Node
* - this Node, meaning the successor is head.next
* - null, meaning there is no successor (this is the last node)
*/ Node<E> next;//下一个节点
Node(E x) { item = x; }
} /** 指定链表容量 */
private final int capacity; /** 当前的元素个数 */
private final AtomicInteger count = new AtomicInteger(0); /** 链表头节点 */
private transient Node<E> head; /** 链表尾节点 */
private transient Node<E> last; /** 出队锁 */
private final ReentrantLock takeLock = new ReentrantLock(); /** 出队等待条件 */
private final Condition notEmpty = takeLock.newCondition(); /** 入队锁 */
private final ReentrantLock putLock = new ReentrantLock(); /** 入队等待条件 */
private final Condition notFull = putLock.newCondition();
2.1、public LinkedBlockingQueue(int capacity)
使用方法:
Queue<String> abq = new LinkedBlockingQueue<String>(1000);
源代码:
/**
* 创建一个 LinkedBlockingQueue,容量为指定容量
*/
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);//初始化头节点和尾节点,均为封装了null数据的节点
}
注意点:
LinkedBlockingQueue的组成一个链表+两把锁+两个条件
2.2、public LinkedBlockingQueue()
使用方法:
Queue<String> abq = new LinkedBlockingQueue<String>();
源代码:
/**
* 创建一个LinkedBlockingQueue,容量为整数最大值
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
注意点:默认容量为整数最大值,可以看做没有容量限制
3、入队:
3.1、public boolean offer(E e)
原理:
在队尾插入一个元素, 如果队列没满,立即返回true; 如果队列满了,立即返回false
使用方法:
abq.offer("hello1");
源代码:
/**
* 在队尾插入一个元素, 容量没满,可以立即插入,返回true; 队列满了,直接返回false
* 注:如果使用了限制了容量的队列,这个方法比add()好,因为add()插入失败就会抛出异常
*/
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
final AtomicInteger count = this.count;// 获取队列中的元素个数
if (count.get() == capacity)// 队列满了
return false;
int c = -1;
final ReentrantLock putLock = this.putLock;
putLock.lock();// 获取入队锁
try {
if (count.get() < capacity) {// 容量没满
enqueue(e);// 入队
c = count.getAndIncrement();// 容量+1,返回旧值(注意)
if (c + 1 < capacity)// 如果添加元素后的容量,还小于指定容量(说明在插入当前元素后,至少还可以再插一个元素)
notFull.signal();// 唤醒等待notFull条件的其中一个线程
}
} finally {
putLock.unlock();// 释放入队锁
}
if (c == 0)// 如果c==0,这是什么情况?一开始如果是个空队列,就会是这样的值,要注意的是,上边的c返回的是旧值
signalNotEmpty();
return c >= 0;
}
/**
* 创建一个节点,并加入链表尾部
* @param x
*/
private void enqueue(E x) {
/*
* 封装新节点,并赋给当前的最后一个节点的下一个节点,然后在将这个节点设为最后一个节点
*/
last = last.next = new Node<E>(x);
}
private void signalNotEmpty() {
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();//获取出队锁
try {
notEmpty.signal();//唤醒等待notEmpty条件的线程中的一个
} finally {
takeLock.unlock();//释放出队锁
}
}
如果,入队逻辑不懂,查看最后总结部分入队逻辑的图,代码非常简单,流程看注释即可。
3.2、public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException
原理:
在队尾插入一个元素,,如果队列已满,则进入等待,直到出现以下三种情况:
被唤醒
等待时间超时
当前线程被中断
使用方法:
try {
abq.offer("hello2",1000,TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
源代码:
/**
* 在队尾插入一个元素,,如果队列已满,则进入等待,直到出现以下三种情况:
* 1、被唤醒
* 2、等待时间超时
* 3、当前线程被中断
*/
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException { if (e == null)
throw new NullPointerException();
long nanos = unit.toNanos(timeout);// 转换为纳秒
int c = -1;
final ReentrantLock putLock = this.putLock;// 入队锁
final AtomicInteger count = this.count;// 总数量
putLock.lockInterruptibly();
try {
while (count.get() == capacity) {// 容量已满
if (nanos <= 0)// 已经超时
return false;
/*
* 进行等待: 在这个过程中可能发生三件事:
* 1、被唤醒-->继续当前这个while循环
* 2、超时-->继续当前这个while循环
* 3、被中断-->抛出中断异常InterruptedException
*/
nanos = notFull.awaitNanos(nanos);
}
enqueue(e);// 入队
c = count.getAndIncrement();// 入队元素数量+1
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
return true;
}
注意:
awaitNanos(nanos)是AQS中的一个方法,这里就不详细说了,有兴趣的自己去查看AQS的源代码。
免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 LESS+to+MCSS
【推荐】 BRVAH(让RecyclerView变得更高效) (2)
【推荐】 微服务化之缓存的设计
LinkedBlockingQueue源码解析(1)的更多相关文章
- 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源码解析(2)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 3.3.public void put(E e) throws InterruptedException 原 ...
- 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 ...
随机推荐
- [leetcode]199. Binary Tree Right Side View二叉树右视图
Given a binary tree, imagine yourself standing on the right side of it, return the values of the nod ...
- php Pthread 多线程 (一) 基本介绍
我们可以通过安装Pthread扩展来让PHP支持多线程. 线程,有时称为轻量级进程,是程序执行的最小单元.线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,它与同属 ...
- Spring框架的IOC之注解方式的快速入门
1. 步骤一:导入注解开发所有需要的jar包 * 引入IOC容器必须的6个jar包 * 多引入一个:Spring框架的AOP的jar包,spring-aop的jar包 2. 步骤二:创建对应的包结构, ...
- myschool 相思树
题目描述 一群妖王排成一排站在苦情巨树下,寻找自己的转世恋人.虽然都是妖王,但按照涂山的规定必须进行标号,标号为1的妖王排在最后面,标号为n的妖王排在最前面.每个妖王只有一个妖力值a[i]表示它们现在 ...
- linux 操作笔记
1.设置防火墙,允许用户使用http访问本机 [root@localhost geoserver]# systemctl enable httpdCreated symlink from /etc/s ...
- 白盒静态自动化测试工具:PMD使用指南
参考文献:http://www.oschina.net/p/pmd/http://www.cnblogs.com/flyme/archive/2011/09/09/2172548.htmlhttp:/ ...
- npm 如何设置镜像站为淘宝网
转载 2015年06月24日 17:12:12 10542 淘宝镜像:http://npm.taobao.org/ 镜像使用方法(三种办法任意一种都能解决问题,建议使用第三种,将配置写死,下次用的时候 ...
- centos6.5 redis 安装配置及java调用
1.安装gcc 执行命令 yum install gcc 2. 安装ruby环境 yum install ruby yum install rubygems gem install redis 下载 ...
- 卡特尔16PF性格测试与答案
大学生在职业生涯规划时,必须充分注意到自己的性格和职业的适宜性.性格是指一个人在生活中形成的对现实的稳定的态度和行为方式.研究表明,性格影响着一个人的职业取向,由于性格的不同,每个人对工作和职业的态度 ...
- hdu-1877(大数+进制转换)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1877 思路:注意考虑0,0的情况. #include<iostream> #include ...