深入LinkedBlockingQueue实现原理
学习BlockingQueue之LinkedBlockingQueue实现原理
一:概念
LinkedBlockingQueue是一个用链表实现的有界阻塞队列。此队列的默认和最大长度为 Integer.MAX_VALUE。此队列按照先进先出的原则对元素进行排序。
与ArrayBlockingQueue的异同:
ArrayBlockingQueue: 必须设置长度容量 底层数组结构 单锁控制
LinkedBlockingQueue:默认Integer最大值 底层链表结构 双锁
二:LinkedBlockingQueue源码实现
不设置容量,默认为Integer的最大值

也支持设置容量

也支持预先将集合设置入队列

两把锁,一个take锁,控制消费者并发,一个put锁,控制生产者并发:


内部维护单向链表结构:

来看一下主要方法:offer与poll
offer方法:
如果e为null或者对列已满,返回false, 然后加锁,其他的生产者会被阻塞,再次判断如果对列里面元素数量小于容量,那么入队,对列的数量也自加,
如果这时对列仍然有空间,会唤醒正在等待的其他生产者,向对列里面放数据。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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; Node<E> node = new Node<E>(e); final ReentrantLock putLock = this.putLock; putLock.lock(); try { if (count.get() < capacity) { enqueue(node); c = count.getAndIncrement(); if (c + 1 < capacity) notFull.signal(); } } finally { putLock.unlock(); } if (c == 0) signalNotEmpty(); return c >= 0; } |
入队方法:

如果是第一次放入数据,效果图:

主要是建立两个连接,让最后一个元素last指向新来的元素,然后将last指针指向新来的。
再来看一下poll方法:取数据
如果对列为空,返回null ,然后加锁,其他想取数据的消费者线程会被阻塞, 如果没有数据释放锁,返回null,对列有数据,则出队,对列自减,
如果出队后对列中还有数据,那么会唤醒正在等待的其他消费者线程来取数据。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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(); c = count.getAndDecrement(); if (c > 1) notEmpty.signal(); } } finally { takeLock.unlock(); } if (c == capacity) signalNotFull(); return x; } |
出队方法:

返回first的item元素,这个链表的头结点维护的都是空节点,效果图如下:
出队前:

出队后:

add 和remove:
add方法: 直接使用父类AbstractQueue的方法:
在offer的基础上进行了保证,成功返回true,false的时候返回异常。

remove方法:

两把锁同时上锁,两把锁同时解锁:

来看一下删除元素的动作:因为数据结构是链表,所以只需要把指向该节点的上一个节点的next变量不指向该节点即可,然后
gc的时候就会把该节点回收掉:
trial.next = p.next 的作用就是让p节点的前一个元素直接指向p的后一个元素,而数组结构就是把该下标置为null object[takeIndex] == null

put和take方法:
put方法:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); // Note: convention in all put/take/etc is to preset local var // holding count negative to indicate failure unless set. int c = -1; 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) { notFull.await(); } enqueue(node); c = count.getAndIncrement(); if (c + 1 < capacity) notFull.signal(); } finally { putLock.unlock(); } if (c == 0) signalNotEmpty(); } |
take方法:
take方法的判断逻辑与poll基本相同,唯一区别是,如果对列没有元素,take为阻塞消费者线程,而poll会返回false。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public E take() throws InterruptedException { E x; int c = -1; final AtomicInteger count = this.count; final ReentrantLock takeLock = this.takeLock; takeLock.lockInterruptibly(); try { while (count.get() == 0) { notEmpty.await(); } x = dequeue(); c = count.getAndDecrement(); if (c > 1) notEmpty.signal(); } finally { takeLock.unlock(); } if (c == capacity) signalNotFull(); return x; } |
深入LinkedBlockingQueue实现原理的更多相关文章
- 20.并发容器之ArrayBlockingQueue和LinkedBlockingQueue实现原理详解
1. ArrayBlockingQueue简介 在多线程编程过程中,为了业务解耦和架构设计,经常会使用并发容器用于存储多线程间的共享数据,这样不仅可以保证线程安全,还可以简化各个线程操作.例如在“生产 ...
- 理解线程池到走进dubbo源码
引言 合理利用线程池能够带来三个好处. 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. ...
- 学习笔记 07 --- JUC集合
学习笔记 07 --- JUC集合 在讲JUC集合之前我们先总结一下Java的集合框架,主要包含Collection集合和Map类.Collection集合又能够划分为LIst和Set. 1. Lis ...
- BlockingQueue 解析
阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列 ...
- BlockingQueue深入解析-BlockingQueue看这一篇就够了
本篇将详细介绍BlockingQueue,以下是涉及的主要内容: BlockingQueue的核心方法 阻塞队列的成员的概要介绍 详细介绍DelayQueue.ArrayBlockingQueue.L ...
- 008 BlockingQueue理解
原文https://www.cnblogs.com/WangHaiMing/p/8798709.html 本篇将详细介绍BlockingQueue,以下是涉及的主要内容: BlockingQueue的 ...
- 生产者消费者模型Java实现
生产者消费者模型 生产者消费者模型可以描述为: ①生产者持续生产,直到仓库放满产品,则停止生产进入等待状态:仓库不满后继续生产: ②消费者持续消费,直到仓库空,则停止消费进入等待状态:仓库不空后,继续 ...
- LinkedBlockingQueue出入队实现原理
类图概述 由类图可以看出,L是单向链表实现的,有两个ReentrantLock实例用来控制元素入队和出队的原子性,takeLock用来控制只有一个线程可以从队头获取元素,putLock控制只有一个线程 ...
- 分布式开放消息系统(RocketMQ)的原理与实践
分布式消息系统作为实现分布式系统可扩展.可伸缩性的关键组件,需要具有高吞吐量.高可用等特点.而谈到消息系统的设计,就回避不了两个问题: 消息的顺序问题 消息的重复问题 RocketMQ作为阿里开源的一 ...
- Java并发集合的实现原理
本文简要介绍Java并发编程方面常用的类和集合,并介绍下其实现原理. AtomicInteger 可以用原子方式更新int值.类 AtomicBoolean.AtomicInteger.AtomicL ...
随机推荐
- Java 10大优点—Part4—Java内存模型
本文由 ImportNew - 靳禹 翻译自 zeroturnaround.如需转载本文,请先参见文章末尾处的转载要求. 在忙着参加在爱沙尼亚进行的 TEDx talk 演讲活动以及在比利时举办的一届 ...
- Python:pygame游戏编程之旅三(玩家控制的小球)
上一节实现了小球自由移动,本节在上节基础上增加通过方向键控制小球运动,并为游戏增加了背景图片. 一.实现: # -*- coding:utf-8 -*- import os import sys im ...
- elementUI 表格之合并同类项(包括行和列)
mergeSpan(tableData, arr) { //["areName","indexCode"] let spanArr = new Array(ta ...
- 震惊!推荐一款AI驱动的自动化测试神器:TestCraft
在当今快速迭代的软件开发环境中,自动化测试已经成为确保软件质量的重要一环.然而,传统的手动录制和编写测试脚本的方式不仅耗时耗力,还难以跟上敏捷开发的节奏. 本文将为大家介绍一款基于AI技术的自动化测试 ...
- 4-CSRF漏洞渗透与防御
1.什么是CSRF漏洞 Cross-Site Request Forgery 跨站请求伪造 从一个第三方的网站,利用其他网站生效的cookie,直接请求服务器的某一个接口,导致攻击发生! 2.CSRF ...
- Redis循环慢接口优化
原慢接口 List<String> keys = new ArrayList<>(Arrays.asList("1", "2", &qu ...
- zustand:基于hooks的react状态管理
react的状态管理 状态(State)是 React 中用于存储组件数据的特殊对象,它可以影响组件的渲染输出.状态管理的核心目标是确保数据的一致性.可预测性以及组件之间的数据流. 每个 React ...
- C语言离散化
C语言离散化 最近看到STL就不想用, 于是写个C语言离散化, 居然能过主席树板子, 就写个博客介绍一下. qsort和bsearch都在<stdlib.h>或<cstdlib> ...
- Redis应用—1.在用户数据里的应用
大纲 1.社区电商的业务闭环 2.Redis缓存架构的典型生产问题 3.用户数据在读多写少场景下的缓存设计 4.热门用户数据的缓存自动延期机制 5.缓存惊群与穿透问题的解决方案 6.缓存和数据库双写不 ...
- 【异或运算】codeforces 1153 B. Dima and a Bad XOR
前言 异或运算:是一种在二进制数系统中使用的逻辑运算.它的基本规则是对两个二进制位进行比较,如果这两个位不同,则结果为 \(1\):如果相同,则结果为 \(0\). 异或运算的规则 \(0\) XOR ...