Java并发编程-阻塞队列(BlockingQueue)的实现原理

DDR的Controller、Channel、Chip、Rank、Bank、Row、Column、Sided、Dimm DDR的Controller、Channel、Chip、Bank、Rank、Row、Column、Sided、Dimm 阅读详情

    阻塞队列 (BlockingQueue)是Java util.concurrent包下重要的数据结构,BlockingQueue提供了线程安全的队列访问方式:当阻塞队列进行插入数据时,如果队列已满,线程将会阻塞等待直到队列非满;从阻塞队列取数据时,如果队列已空,线程将会阻塞等待直到队列非空。并发包下很多高级同步类的实现都是基于BlockingQueue实现的。

BlockingQueue 的操作方法

BlockingQueue 具有 4 组不同的方法用于插入、移除以及对队列中的元素进行检查。如果请求的操作不能得到立即执行的话,每个方法的表现也不同。这些方法如下:

四组不同的行为方式解释:

    抛异常:如果试图的操作无法立即执行,抛一个异常。
    特定值:如果试图的操作无法立即执行,返回一个特定的值(常常是 true / false)。
    阻塞:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行。
    超时:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。返回一个特定值以告知该操作是否成功(典型的是true / false)。

无法向一个 BlockingQueue 中插入 null。如果你试图插入 null,BlockingQueue 将会抛出一个 NullPointerException。

可以访问到 BlockingQueue 中的所有元素,而不仅仅是开始和结束的元素。比如说,你将一个对象放入队列之中以等待处理,但你的应用想要将其取消掉。那么你可以调用诸如 remove(o) 方法来将队列之中的特定对象进行移除。但是这么干效率并不高(译者注:基于队列的数据结构,获取除开始或结束位置的其他对象的效率不会太高),因此你尽量不要用这一类的方法,除非你确实不得不那么做。

BlockingQueue 的实现类

    BlockingQueue 是个接口,你需要使用它的实现之一来使用BlockingQueue,java.util.concurrent包下具有以下 BlockingQueue 接口的实现类:

    ArrayBlockingQueue:ArrayBlockingQueue 是一个有界的阻塞队列,其内部实现是将对象放到一个数组里。有界也就意味着,它不能够存储无限多数量的元素。它有一个同一时间能够存储元素数量的上限。你可以在对其初始化的时候设定这个上限,但之后就无法对这个上限进行修改了(译者注:因为它是基于数组实现的,也就具有数组的特性:一旦初始化,大小就无法修改)。

    DelayQueue:DelayQueue 对元素进行持有直到一个特定的延迟到期。注入其中的元素必须实现 java.util.concurrent.Delayed 接口。

    LinkedBlockingQueue:LinkedBlockingQueue 内部以一个链式结构(链接节点)对其元素进行存储。如果需要的话,这一链式结构可以选择一个上限。如果没有定义上限,将使用 Integer.MAX_VALUE 作为上限。

    PriorityBlockingQueue:PriorityBlockingQueue 是一个无界的并发队列。它使用了和类 java.util.PriorityQueue 一样的排序规则。你无法向这个队列中插入 null 值。所有插入到 PriorityBlockingQueue 的元素必须实现 java.lang.Comparable 接口。因此该队列中元素的排序就取决于你自己的 Comparable 实现。

    SynchronousQueue:SynchronousQueue 是一个特殊的队列,它的内部同时只能够容纳单个元素。如果该队列已有一元素的话,试图向队列中插入一个新元素的线程将会阻塞,直到另一个线程将该元素从队列中抽走。同样,如果该队列为空,试图向队列中抽取一个元素的线程将会阻塞,直到另一个线程向队列中插入了一条新的元素。据此,把这个类称作一个队列显然是夸大其词了。它更多像是一个汇合点。

使用例子:

阻塞队列的最长使用的例子就是生产者消费者模式,也是各种实现生产者消费者模式方式中首选的方式。使用者不用关心什么阻塞生产,什么时候阻塞消费,使用非常方便,代码如下:
 

package MyThread;

import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class BlockingQueueTest {
    //生产者
    public static class Producer implements Runnable{
        private final BlockingQueue<Integer> blockingQueue;
        private volatile boolean flag;
        private Random random;

        public Producer(BlockingQueue<Integer> blockingQueue) {
            this.blockingQueue = blockingQueue;
            flag=false;
            random=new Random();

        }
        public void run() {
            while(!flag){
                int info=random.nextInt(100);
                try {
                    blockingQueue.put(info);
                    System.out.println(Thread.currentThread().getName()+" produce "+info);
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }               
            }
        }
        public void shutDown(){
            flag=true;
        }
    }
    //消费者
    public static class Consumer implements Runnable{
        private final BlockingQueue<Integer> blockingQueue;
        private volatile boolean flag;
        public Consumer(BlockingQueue<Integer> blockingQueue) {
            this.blockingQueue = blockingQueue;
        }
        public void run() {
            while(!flag){
                int info;
                try {
                    info = blockingQueue.take();
                    System.out.println(Thread.currentThread().getName()+" consumer "+info);
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }               
            }
        }
        public void shutDown(){
            flag=true;
        }
    }
    public static void main(String[] args){
        BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<Integer>(10);
        Producer producer=new Producer(blockingQueue);
        Consumer consumer=new Consumer(blockingQueue);
        //创建5个生产者,5个消费者
        for(int i=0;i<10;i++){
            if(i<5){
                new Thread(producer,"producer"+i).start();
            }else{
                new Thread(consumer,"consumer"+(i-5)).start();
            }
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        producer.shutDown();
        consumer.shutDown();

    }
}

阻塞队列原理:

其实阻塞队列实现阻塞同步的方式很简单,使用的就是是lock锁的多条件(condition)阻塞控制。使用BlockingQueue封装了根据条件阻塞线程的过程,而我们就不用关心繁琐的await/signal操作了。

下面是Jdk 1.7中ArrayBlockingQueue部分代码:
 

public ArrayBlockingQueue(int capacity, boolean fair) {

        if (capacity <= 0)
            throw new IllegalArgumentException();
        //创建数组    
        this.items = new Object[capacity];
        //创建锁和阻塞条件
        lock = new ReentrantLock(fair);   
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }
//添加元素的方法
public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length)
                notFull.await();
            //如果队列不满就入队
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }
 //入队的方法
 private void enqueue(E x) {
        final Object[] items = this.items;
        items[putIndex] = x;
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        notEmpty.signal();
    }
 //移除元素的方法
 public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
            lock.unlock();
        }
    }
 //出队的方法
 private E dequeue() {
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        E x = (E) items[takeIndex];
        items[takeIndex] = null;
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        notFull.signal();
        return x;

双端阻塞队列(BlockingDeque)

concurrent包下还提供双端阻塞队列(BlockingDeque),和BlockingQueue是类似的,只不过BlockingDeque提供从任意一端插入或者抽取元素的队列。

其他文章:
Java并发编程-并发工具包(java.util.concurrent)使用指南(全)

 

 

 

【图论】系列(七)图论的中心性度量方法及重要性评价指标 图论中的中心性度量方法是用来衡量图中各个节点(或顶点)相对重要性的指标。 阅读详情

相关推荐

win11本地部署openclaw实操第5集-X11图形化界面搭建,让WSL2“看见”世界

本文介绍了在WSL2中实现图形界面(GUI)的方法。由于WSL2默认没有图形界面,需要使用X11服务器作为"翻译显示器",将Linux程序的图形指令渲染到Windows窗口中。推荐使用VcXsrv作为X11服务器,详细说明了其安装和配置步骤,包括选择"One large window"显示模式、禁用访问控制等关键设置。随后在Ubuntu中安装轻量级xfce4桌面环境,并通过设置DISPLAY环境变量将图形输出指向VcXsrv。最终通过startxfce4命令成功在Vc

weixin_44626085的博客 811

js生成二维码——QRCode.js中文文档

QRCode v1.2.2 原文地址 API文档 一、安装 项目文件夹中执行 npm install --save qrcode 或者,全局安装 npm install -g qrcode 二、使用 在javascript中使用 Module bundlers &lt;!-- index.html --&gt; &lt;html&gt; &lt;body&gt; &lt;ca...

weixin_42854769的博客 2万+

在 Ansys Mechanical 中使用“螺栓工具”插件自动生成螺栓

在有限元分析 (FEA) 中,高效创建螺栓连接对于确保机械装配的结构完整性和性能至关重要。螺栓是连接组件不可或缺的一部分,它们在负载下的精确建模会影响整个系统。快速高效的螺栓建模使工程师能够快速优化设计,满足紧迫的期限,并通过为其他关键设计任务释放资源来提高整体生产力。此外,螺栓建模的精度可以最大限度地降低模型创建过程中出错的风险,这对于获得可靠和准确的分析结果至关重要。因此,在 FEA 中快速且无错误地创建螺栓连接对于高效、可靠和成功的工程结果至关重要。

jkh920184196的博客 3101

JavaScript:二维码生成与解析

JavaScript:二维码的生成与解析

前端御书房 7303

【NAS系统】DSM7.2部署SVN服务

早期的群晖版本可以在套件中心找到SVN Server直接安装,然后配置仓库和用户。但‌2提到DSM7.0之后套件中心没有SVN了,得用Docker。

qq_38350004的博客 4847

HUMAnN 3.0 (alpha)安装及使用

文章目录简介安装数据库下载运行参考 简介 安装 conda install humann humann_test (~1 minute) 数据库下载 humann_databases --download chocophlan full /path/to/databases --update-config yes humann_databases --download uniref uniref90_diamond /path/to/databases --update-config yes humann_

dys的博客 9505

QRCode 生成和下载二维码

使用注意事项: 1.url必须带通信协议 2.生成二维码前必须先清空二维码,不然会重复生成二维码(文章最后) 一、引入插件QRCode QRCode.js 是一个用于生成二维码的 JavaScript 库。主要是通过获取 DOM 的标签,再通过 HTML5 Canvas 绘制而成,不依赖任何库。 (偷懒链接) https://static.runoob.com/download/qrcodejs-04f46c6.zip 二、基本使用 <div id="qrcode"></div&g.

bai_pd的博客 8516

A B C三个气象站的小波分析结果解读

在小波分析的过程中,信号的不同频率分量会在不同的尺度上显现,而纵轴上的数值表示信号在相应尺度上的强度或能量。2. **小波方差的横轴(水平轴)**:横轴上的尺度表示用于分析的小波函数的尺度。1. **共同趋势:** 在所有三个点的小波方差图中,随着尺度的增加,方差逐渐增大,尤其是在较大的时间尺度上。3. **尺度30的特殊性:** 在所有点的小波方差图中,尺度30似乎是一个特殊的点,对应着一个较长的时间尺度上的波动或变化。2. **方差的大小:** 方差的大小反映了在相应尺度下信号的波动强度。

weixin_44259522的博客 859

JS生成二维码QRCode代码

JavaScript是一种广泛使用的前端编程语言,它不仅用于网页交互,还可以实现许多实用功能,如生成二维码。本篇文章将深入探讨如何使用JavaScript生成二维码,以及如何确保这种生成的二维码在各种浏览器和手机端都能正常工作,并支持包含中文内容。

专注企业级视频应用,企业视频直播、MR虚拟直播、教育培训连麦直播 2045

基于迁移学习的花卉识别系统

本研究采用了预训练的经典深度学习模型,包括ResNet、AlexNet和VGG,通过微调的方式在Oxford-102数据集和一个自制花卉数据集上进行训练,并对图像进行了多种数据增强操作,以提高模型的泛化能力,致力于实现花卉的高效分类。

m0_71146337的博客 2375

前程无忧Python岗位数据采集:基于API直连的高效招聘信息爬取实战

本文介绍了一个基于Python requests库的前程无忧招聘数据采集系统。项目通过分析API接口结构,配置完整的请求头和身份验证参数,实现了高效稳定的数据采集。系统支持多页数据批量获取,包含工作名称、薪资范围等关键字段的结构化解析,并将结果存储为Excel文件。技术实现涉及API分析、身份验证、请求头配置、数据清洗等关键步骤,同时强调遵守法律和道德规范。该系统可为求职者、HR和市场分析师提供有价值的行业数据支持,适用于市场分析、职业规划等场景。

那些看似不起波澜的日复一日,会在某天让你看到坚持的意义 1552

【JUC并发编程】BlockingQueue实现原理(BlockingQueue接口/ Java阻塞队列)

目录1. 简单回顾数据结构2. 数组结构3. 链表结构4. Lock锁使用回顾5. 什么是阻塞队列6. BlockingQueue接口7. 有界与无界区别8. Java里的阻塞队列8.1 ArrayBlockingQueue8.2 ArrayBlockingQueue8.3 ArrayBlockingQueue 实现生产者与消费者模型8.4 纯手写ArrayBlockingQueue8.5 LinkedBlockingQueue8.6 ArrayBlockingQueue 与LinkedBlockingQ

记录各种Bug解决案例及日常学习内容 917

Skill的嵌套

Skill的嵌套就很简单,直接引用其他的Skill就好了。在一个 Skill 的 SKILL.md 中,可以明确指示 Claude 去读取另一个 Skill 的文档。

Criss@陈磊 956

Java并发:阻塞队列BlockingQueue实现原理分析

可能有人会问我为什么愿意去花时间帮助大家实现求职梦想,因为我一直坚信时间是可以复制的。我牺牲了自己的大概十个小时写了这片文章,换来的是成千上万的求职者节约几天甚至几周时间浪费在无用的资源上。上面的这些(算法与数据结构)+(Java多线程学习手册)+(计算机网络顶级教程)等学习资源《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)**

2401_84414990的博客 801

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Java 并发编程(四)-阻塞队列

一、读写锁 1、悲观锁和乐观锁 悲观锁:先上锁,再操作,操作完解锁。不支持并发操作。 乐观锁:只是在修改完成后,提交时对数据进行上锁比较数据的完整性。 2、表锁和行锁 表锁:操作表中某一条数据会把整张表进行锁住。表锁不会发生死锁。 行锁:操作表中的某一行数据,对这行数据进行锁定。行锁会发生死锁。 3、读锁和写锁 读锁:共享锁。读锁会发生死锁。 写锁:独占锁。写锁会发生死锁。 读写锁:一个资源可以被多个读线程访问,或者可以被一个写线程访问,但是不能同时存在读写线程。读写互斥,读读共享。 例

杀神lwz的博客 961

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Java 阻塞队列BlockingQueue接口

对于阻塞队列BlockingQueue的学习,予以记录!BlockingQueue接口类似于list接口,①阻塞队列有没有好的一面?②不得不阻塞,如何管理?类似ArrayList用法。

qq_43357394的博客 245

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Java 阻塞队列--BlockingQueue

1. 什么是阻塞队列? 阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。 阻塞队列提供了四种处理方法: 方法\处理方式 抛出异常 返回特殊值

Firstlucky77的博客 9855

BlockingQueue(阻塞队列)简单易懂

首先我们先了解: 栈:先进后出 队列:先进后出 阻塞:必须要阻塞/不得不阻塞 阻塞队列是一个队列,在数据结构中起的作用如下图: 线程1往阻塞队列里添加元素,线程2从阻塞队列里移除元素 当队列是空的,从队列中获取元素的操作将会被阻塞 当队列是满的,从队列中添加元素的操作将会被阻塞 试图从空的队列中获取元素的线程将会被阻塞,直到其他线程往空的队列插入新的元素 试图向已满的队列中添加新元素的线程将会被阻塞,直到其他线程从队列中移除一个或多个元素或者完全清空,使队列变得空闲起来并后续新增 用处: 在多线程领域:所

细数长流 446

Java~并发容器ConcurrentHashMap、ConcurrentLinkedQueue、阻塞队列BlockingQueue的实现原理与使用

文章目录ConcurrentHashMap对比HashMap和HashTableConcurrentHashMap的结构原理get操作put操作size操作ConcurrentLinkedQueueConcurrentLinkedQueue的结构原理入队列出队列阻塞队列BlockingQueueJava里的六个阻塞队列(了解) ConcurrentHashMap对比HashMap和HashTable 在并发编程中使用HashMap可能导致程数据序数据出错严重还会导致死循环。而使用线程安全的HashTabl

Shangxingya的博客 812
上一篇: Java开发中的23种设计模式详解 整理
下一篇: mysql安装失败原因和解决方法
CWS_chen
博客等级 码龄11年 220粉丝 51原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值