LinkedBlockingQueue出入队实现原理
类图概述
由类图可以看出,L是单向链表实现的,有两个ReentrantLock实例用来控制元素入队和出队的原子性,takeLock用来控制只有一个线程可以从队头获取元素,putLock控制只有一个线程可以从队尾添加元素。notEmpty和notFull是条件变量,内部有条件队列用来存放进队和出队被阻塞的线程。

阻塞入队
put操作:在队尾插入元素,如果队列已满则阻塞当前线程,直到队列有空闲插入成功后返回。如果在阻塞时被其他线程设置中断标志,线程会抛出异常而返回。(中断是一种线程协作的方式)
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
final int c;
final Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
/*
* Note that count is used in wait guard even though it is
* not protected by lock. This works because count can
* only decrease at this point (all other puts are shut
* out by lock), and we (or some other waiting put) are
* signalled if it ever changes from capacity. Similarly
* for all other uses of count in other wait guards.
*/
while (count.get() == capacity) { (3)
notFull.await();
}
enqueue(node); (4)
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
代码(3)如果队列满了,调用await放入条件队列,当前线程被阻塞挂起后会释放获取到的putLock锁,所以其他线程就有机会获取到putLock锁了。
另外,在判断队列是否为空时为何使用while而不是if?这是考虑当前线程被虚假唤醒的问题,如果使用if语句,那么虚假唤醒后会执行(4)的入队操作,并且递增计数器,而这时候队列已经满了,从而导致队列元素溢出。而使用while循环时,假如await被虚假唤醒了,那么在此循环检查当前队列是否已满,如果是则在此进行等待。
虚假唤醒:多个等待线程在满足if条件时都会被唤醒(虚假的),但实际上条件并不满足,生产者生产出来的消费品已经被第一个线程消费了。
结论:对条件变量的状态进行不断检查直到其满足条件。
阻塞出队
take操作:当线程获取到锁,其他调用take or poll的线程会被阻塞挂起(ReentrantLock内部的AQS)。如果队列为空,将当前线程放入条件队列中。
Reference
《Java并发编程之美》
LinkedBlockingQueue出入队实现原理的更多相关文章
- React直出实现与原理
前一篇文章我们介绍了虚拟DOM的实现与原理,这篇文章我们来讲讲React的直出. 比起MVVM,React比较容易实现直出,那么React的直出是如何实现,有什么值得我们学习的呢? 为什么MVVM不能 ...
- MySQL 页完全指南——浅入深出页的原理
之前写了一些关于 MySQL 的 InnoDB 存储引擎的文章,里面好几次都提到了页(Pages)这个概念,但是都只是简要的提了一下.例如之前在聊 InnoDB内存结构 时提到过,但当时的重点是内存架 ...
- 使用.NetCore自带的后台作业,出入队简单模拟生产者消费者处理请求响应的数据
环境:Core:3.1的项目 说明:由于该方案为个人测试项目,重启时队列中的部分数据很可能会丢失, 对数据有要求的该方案不适用,不能照搬需要持久化处理, 另外发布到Linux Docker中通常不会自 ...
- 源代码解读Cas实现单点登出(single sign out)功能实现原理--转
关于Cas实现单点登入(single sing on)功能的文章在网上介绍的比较多,想必大家多多少少都已经有所了解,在此就不再做具体介绍.如果不清楚的,那只能等我把single sign on这块整理 ...
- PHP 弹出文件下载 原理 代码
/** * @author default7<default7@zbphp.com> * @description 演示PHP弹出下载的原理 * * @param $file_n ...
- Java同步数据结构之LinkedBlockingQueue
前言 比起ArrayBlockingQueue,LinkedBlockingQueue应该是最被大家常用的阻塞队列,LinkedBlockingQueue是基于链表的一种可选容量的阻塞队列,也就是说, ...
- 11.并发包阻塞队列之LinkedBlockingQueue
在上文<10.并发包阻塞队列之ArrayBlockingQueue>中简要解析了ArrayBlockingQueue部分源码,在本文中同样要介绍的是Java并发包中的阻塞队列LinkedB ...
- 并发队列 – 有界阻塞队列 ArrayBlockingQueue 原理探究
一.ArrayBlockingQueue类图结构 如图ArrayBlockingQueue内部有个数组items用来存放队列元素,putindex下标标示入队元素下标,takeIndex是出队下标,c ...
- Go语言GC实现原理及源码分析
转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com/archives/475 本文使用的 Go 的源码1.15.7 介绍 三色标记法 三色标 ...
- 面试侃集合 | LinkedBlockingQueue篇
面试官:好了,聊完了ArrayBlockingQueue,我们接着说说LinkedBlockingQueue吧 Hydra:还真是不给人喘口气的机会,LinkedBlockingQueue是一个基于链 ...
随机推荐
- git 代码托管常用代码
一.git全局账号登录 (1)全局登录账号和密码 git config --global user.name "xxx" git config --global user.emai ...
- STM32cubemx-HAL库串口断线问题
STM32cubemx:version5.1 Chip: STM32F446RE IDE:Keil5 Q:小项目上写了个简单的通信包,波特率230400,数据量较大1600Byte/s,DMA的方式实 ...
- Ubuntu ROOT默认密码设置
Ubuntu默认密码设置 Ubuntu默认是不设置ROOT密码的,如果需要安装一些包则需要从普通用户调转至ROOT用户,这个时候就需要设置一下密码了. 下面这种情况 chen@chen:~/Deskt ...
- 5、MySQL中的锁
1.6. MySQL中的锁 InnoDB中锁非常多,总的来说,可以如下分类: 这些锁都是做什么的?具体含义是什么?我们现在来一一学习. 1.6.1.解决并发事务问题 我们已经知道事务并发执行时可能带来 ...
- 内存、cpu、硬盘使用率测试方法
平时测试过程中经常需要测试页面展示的系统资源信息是否正确,比如CPU.内存.硬盘等,一般是需要测试服务器的资源情况,服务器一般部署在linux上,今天总结一下测试方法: 1.CPU测试:(使用shel ...
- 模拟实现call,apply,bind方法,以及三者区别
// 模拟实现call方法 Function.prototype.call2 = function (context) { var context = context || window; conte ...
- django_静态文件
**************************************************************************************************** ...
- SDN实验1
(一)基本要求 使用Mininet可视化工具,生成下图所示的拓扑,并保存拓扑文件名为学号.py. 使用Mininet的命令行生成如下拓扑: a) 3台交换机,每个交换机连接1台主机,3台交换机连接成一 ...
- "蔚来杯"2022牛客暑期多校训练营1 C.Grab the Seat!
C.Grab the Seat! 题目链接 https://ac.nowcoder.com/acm/contest/33186/C 题目大意 1.二维平面中,(0,1) - (0,m)为屏幕 2.有n ...
- java的3中代理模式
代理模式是什么 代理模式是一种设计模式,简单说即是在不改变源码的情况下,实现对目标对象的功能扩展. 比如有个歌手对象叫Singer,这个对象有一个唱歌方法叫sing(). 1 public class ...