ArrayBlockingQueue实际应用场景


之前在某公司做过一款情绪识别的系统,这套系统通过调用摄像头接口采集人脸信息,将采集的人脸信息做人脸识别和情绪分析,最终经过一定的算法将个人情绪数据转化具体行为指标值。其中采集图片的部分就用到了并发队列ArrayBlockingQueue。

如上图所示:摄像头有n个,单线程采集的效率会比较慢,所以在采集摄像头的过程中是多线程的,另外采集到的图片需要存储到图片服务器,对图片服务器写也有很高的要求,图片服务器是集群的,也需要用到也多线程的。将图片入库后需要将图片数据打到人脸分析服务器上去处理,这部分涉及到了分布式消息,所以是黑色虚线部分用kafka来传递消息。其中红色虚线部分多线程图片采集将信息传递到多线程图片存储用到了ArrayBlockingQueue,它是并发安全队列

ArrayBlockingQueue简化类图结构


从类图可以看出Queue接口提供了add,offer入队列的方法,提供poll出队列的方法!

BlockingQueue接口增加了put入队列的方法,提供take出队列的方法!

补充说明:UML类图结构:

  • 继承:实线空箭头。
  • 实现:虚线虚箭头。

 

并发队列阻塞和非阻塞概念


从上面类图名字可以看到Queue提供的方法是非阻塞的!而BlockingQueue提供的put,take方法是阻塞的!下面按老思路,我们用代码说明阻塞非阻塞下!

非阻塞

import java.util.concurrent.ArrayBlockingQueue;

/**
* @author :jiaolian
* @date :Created in 2021-02-02 20:16
* @description:ArrayBlockingQueue阻塞非阻塞测试
* @modified By:
* 公众号:叫练
*/
public class ArrayBlockingQueueTest {
public static void main(String[] args) {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);
arrayBlockingQueue.offer("叫练");
arrayBlockingQueue.offer("叫练");
//输出arrayBlockingQueue的长度
System.out.println(arrayBlockingQueue.size());
}
}

如上代码:设置ArrayBlockingQueue长度为1,通过offer方法向队列添加2个元素,最后打印arrayBlockingQueue的长度?答案是1,不会阻塞,因为offer方法丢弃了第二个元素“叫练”,我们说出队和入队能够让其继续执行的队列我们称为非阻塞。如果换成add方法呢?就会报错队列溢出,如下图所示!但是还不是阻塞的。下面我们看看什么阻塞!

阻塞

import java.util.concurrent.ArrayBlockingQueue;

/**
* @author :jiaolian
* @date :Created in 2021-02-02 20:16
* @description:ArrayBlockingQueue阻塞非阻塞测试
* @modified By:
* 公众号:叫练
*/
public class ArrayBlockingQueueTest {
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);
arrayBlockingQueue.put("叫练");
arrayBlockingQueue.put("叫练");
//输出arrayBlockingQueue的长度
System.out.println(arrayBlockingQueue.size());
}
}

如上代码:ArrayBlockingQueue长度为1,通过put方法向队列添加2个元素,最后输出arrayBlockingQueue的长度是多少?答案是控制台一直运行,因为在添加第二个“叫练”时程序阻塞了。我们说出队和入队不能够让其继续执行的队列我们称为阻塞,add方法,poll方法,take方法我们就不一一举例了,大家可以写代码做下最简单的测试!

好啦,我们对几个方法做个总结吧!

  • 入队:

offer:队列满了丢弃。

add :队列满了报错。

put :阻塞。

  • 出队:

poll :如果队列为空则返回null。

take :阻塞。

ArrayBlockingQueue实现原理浅析


如上图,ArrayBlockingQueue是用数组实现的,ReentrantLock独占锁控制数组的入队和出队。notEmpty,notFull是ReentrantLock的两个条件队列,用来控制队列是否进入阻塞状态,是生产者和消费者模型。下面我们看看take,put方法流程,其他的方法同理。

  • take方法:多个线程竞争独占锁获取items[taskIndex]队首元素,其中A线程成功获取锁,其他线程阻塞等待A线程执行完成释放锁,如果队列不为空,A线程获取items[taskIndex]元素返回移除并释放锁让其他阻塞线程继续竞争;如果队列为空,A线程调用notEmpty.await方法进入条件队列并释放锁让其他阻塞线程继续竞争,其他线程发现队列为空也会进入notEmpty条件队列,等待put线程入队通知notEmpty阻塞线程。
  • put方法:多个线程竞争独占锁设置items[putIndex]队尾元素,其中A线程成功获取锁,其他线程阻塞等待A线程执行完成释放锁,如果队列不满【队列长度】,A线程添加items[putIndex]元素返回并释放锁让其他阻塞线程继续竞争;如果队列满了,A线程调用notFull.await方法进入条件队列并释放锁让其他阻塞线程继续竞争,其他线程发现队列为空也会进入notFull条件队列,等待take线程出队通知notFull阻塞线程

完全非阻塞队列ConcurrentLinkedQueue


ConcurrentLinkedQueue也实现了Queue接口,提供offer,add,poll方法都是非阻塞的,另外从名字可以看出,底层是链表结构,入队和出队用的是自旋的cas。

List 多线程安全方案:LinkedBlockingQueue


LinkedBlockingQueue和ArrayBlockingQueue 类似,LinkedBlockingQueue是有界的,长度是Integer.MAX_VALUE实现上,LinkedBlockingQueue是链表,而且是双锁,如上图所示,takeLock独占锁控制队列头部,putLock控制队列尾部,互不影响,目的是提高LinkedBlockingQueue的并发度。

总结


今天我们介绍了并发队列重要的几个概念,整理出来希望能对你有帮助,写的比不全,同时还有许多需要修正的地方,希望亲们加以指正和点评,年前这段时间会继续输出线程池这些概念等。最后喜欢的请点赞加关注哦。点关注,不迷路,我是叫练【公众号】,边叫边练。

参考书籍:《Java并发编程之美》

并发队列:ArrayBlockingQueue实际运用场景和原理的更多相关文章

  1. JAVA并发(6)-并发队列ArrayBlockingQueue

    本文讲ArrayBlockingQueue 1. 介绍 一个基于数组的有界阻塞队列,FIFO顺序.支持等待消费者和生产者线程的可选公平策略(默认是非公平的).公平的话通常会降低吞吐量,但是可以减少可变 ...

  2. 并发队列ConcurrentLinkedQueue、阻塞队列AraayBlockingQueue、阻塞队列LinkedBlockingQueue 区别和使用场景总结

      三者区别与联系: 联系,三者 都是线程安全的.区别,就是 并发  和 阻塞,前者为并发队列,因为采用cas算法,所以能够高并发的处理:后2者采用锁机制,所以是阻塞的.注意点就是前者由于采用cas算 ...

  3. 自己总结 :并发队列ConcurrentLinkedQueue、阻塞队列AraayBlockingQueue、阻塞队列LinkedBlockingQueue 区别 和 使用场景总结

    并发队列ConcurrentLinkedQueue.阻塞队列AraayBlockingQueue.阻塞队列LinkedBlockingQueue 区别 和  使用场景总结 分类: Java2013-0 ...

  4. 并发编程(八)—— Java 并发队列 BlockingQueue 实现之 ArrayBlockingQueue 源码分析

    开篇先介绍下 BlockingQueue 这个接口的规则,后面再看其实现. 阻塞队列概要 阻塞队列与我们平常接触的普通队列(LinkedList或ArrayList等)的最大不同点,在于阻塞队列的阻塞 ...

  5. 并发队列之ArrayBlockingQueue

    上一篇我们说了并发队列中的LinkedBlockingQueue队列,这次我们看看ArrayBlockingQueue,看看名字,我们想象一下LinkedList和ArrayList的区别,我们可以知 ...

  6. 并发编程-concurrent指南-阻塞队列-数组阻塞队列ArrayBlockingQueue

    ArrayBlockingQueue类是实现了BlockingQueue. ArrayBlockingQueue是一个有界的阻塞队列,其内部实现是将对象放在一个数组中. 放入元素方法: (1) add ...

  7. 【Java并发】并发队列与线程池

    并发队列 阻塞队列与非阻塞队 ConcurrentLinkedQueue BlockingQueue ArrayBlockingQueue LinkedBlockingQueue PriorityBl ...

  8. 解读 java 并发队列 BlockingQueue

    点击添加图片描述(最多60个字)编辑 今天呢!灯塔君跟大家讲: 解读 java 并发队列 BlockingQueue 最近得空,想写篇文章好好说说 java 线程池问题,我相信很多人都一知半解的,包括 ...

  9. 10分钟搞定 Java 并发队列好吗?好的

    | 好看请赞,养成习惯 你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it ...

随机推荐

  1. 杭电OJ:1089----1096(c++)(ACM入门第一步:所有的输入输出格式)

    1089:输入输出练习的A + B(I) 问题描述 您的任务是计算a + b. 太容易了?!当然!我专门为ACM初学者设计了这个问题. 您一定已经发现某些问题与此标题具有相同的名称,是的,所有这些问题 ...

  2. 对数几率回归(逻辑回归)原理与Python实现

    目录 一.对数几率和对数几率回归 二.Sigmoid函数 三.极大似然法 四.梯度下降法 四.Python实现 一.对数几率和对数几率回归   在对数几率回归中,我们将样本的模型输出\(y^*\)定义 ...

  3. CSS&&label_div

    Css-div部分 本章主要内容 0.基础知识 1.CSS概述 2.CSS基础语法 3.CSS选择器 4.CSS主要属性 5.CSS核心机制-盒子模型 6.CSS重点和难点-定位 7.综合示例 基础知 ...

  4. 微信开发所需要的的方法(签名认证、数组转字符串方法、将xml字符串转换为数组、发送xml请求方法)

    //将xml字符串转换为数组 public function xmlToArray($xml){ $array_data = json_decode(json_encode(simplexml_loa ...

  5. 【剑指 Offer】03.数组中重复的数字

    题目描述 找出数组中重复的数字. 在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次.请找出数组中 ...

  6. .NET 云原生架构师训练营(模块二 基础巩固 敏捷开发)--学习笔记

    2.7.1 敏捷开发 敏捷介绍 敏捷的起源 敏捷软件开发宣言 敏捷开发十二原则 生命周期对比 敏捷开发的特点 敏捷的发展 敏捷的核心 敏捷的起源 2001年,17个老头子在一起一边滑雪,一边讨论工作, ...

  7. Nginx基础知识学习(安装/进程模型/事件处理机制/详细配置/定时切割日志)

    一.Linux下Nginx的安装 1.去官网 http://nginx.org/download/下载对应的Nginx安装包,推荐使用稳定版本. 2.上传Nginx到Linux服务器. 3.安装依赖环 ...

  8. Head First 设计模式 —— 14. 复合 (Compound) 模式

    复合模式 在一个解决方案中结合两个或多个模式,以解决一般或重复发生的问题. P500 思考题 public interface Quackable { public void quack(); } p ...

  9. MySQL常用的数据类型和字段属性

    数据类型 数值 tinyint 十分小的数据 1个字节 smallint 较小的数据 2个字节 mediumint 中等大小的数据 3个字节 int 标准的整数 4个字节 常用 bigint 较大的数 ...

  10. SDUST数据结构 - chap1 绪论

    一.判断题: 二.选择题: