Java阻塞队列:ArrayBlockingQueue

Java阻塞队列:ArrayBlockingQueue

ArrayBlockingQueue是Java中的一个阻塞队列(Blocking Queue)实现,它是线程安全的,并且基于数组实现。ArrayBlockingQueue常用于生产者-消费者模型,在这种模型中,生产者线程负责将元素放入队列,而消费者线程负责从队列中取出元素。

ArrayBlockingQueue是一个有界队列,这意味着它有一个固定的容量。在队列已满时,试图向队列中添加元素的操作将被阻塞,直到队列有空间可用。同样地,在队列为空时,试图从队列中取出元素的操作也将被阻塞,直到队列中有可用的元素。

主要特性

  • 线程安全ArrayBlockingQueue内部使用锁和条件变量来确保线程安全。
  • 有界:队列的容量在创建时指定,并且无法改变。
  • FIFO顺序:元素按照先进先出的顺序进行处理。

构造方法

ArrayBlockingQueue提供了多个构造方法,常用的有以下两种:

public ArrayBlockingQueue(int capacity)
public ArrayBlockingQueue(int capacity, boolean fair)
  • capacity:指定队列的容量。
  • fair:指定是否使用公平策略。如果设置为true,则队列的操作将按照公平的顺序进行;否则,不保证公平性。

主要方法

  • put(E e):将指定元素添加到队列中,如果队列已满,则等待空间可用。
  • take():从队列中获取并移除元素,如果队列为空,则等待元素可用。
  • offer(E e):尝试将指定元素添加到队列中,如果队列已满,则返回false
  • poll():从队列中获取并移除元素,如果队列为空,则返回null

使用场景

ArrayBlockingQueue非常适合以下场景:

  • 生产者-消费者模型:多个生产者线程向队列中添加任务,多个消费者线程从队列中取出任务进行处理。
  • 线程池:用于存放待处理任务的队列,线程池中的工作线程从队列中取出任务并执行。

示例代码

下面是一个简单的示例,展示了如何使用ArrayBlockingQueue实现生产者-消费者模型。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ProducerConsumerExample {
    private static final int CAPACITY = 10;
    private static final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(CAPACITY);

    public static void main(String[] args) {
        Thread producer = new Thread(new Producer());
        Thread consumer = new Thread(new Consumer());

        producer.start();
        consumer.start();
    }

    static class Producer implements Runnable {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 20; i++) {
                    System.out.println("Produced: " + i);
                    queue.put(i);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    static class Consumer implements Runnable {
        @Override
        public void run() {
            try {
                while (true) {
                    int value = queue.take();
                    System.out.println("Consumed: " + value);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

线程安全

ArrayBlockingQueue的线程安全性主要依赖于内部的锁机制和条件变量来管理并发访问。这种设计确保了多个线程可以安全地进行入队和出队操作,而不会导致数据不一致或其他并发问题。具体来说,ArrayBlockingQueue通过以下几种方式实现线程安全:

ReentrantLock

ArrayBlockingQueue使用java.util.concurrent.locks.ReentrantLock来管理对共享资源的访问。ReentrantLock是一种可重入的互斥锁,允许同一个线程多次获得锁而不会导致死锁。ArrayBlockingQueue通常会使用两种锁:

  • 主锁(Main Lock):用于保护队列的所有变更操作,如插入、删除等。
  • 分离锁(Separate Locks):在某些实现中,可能会为插入和删除操作使用不同的锁,以减少锁竞争并提高并发性能。

ArrayBlockingQueue中,通常只有一个锁来保护整个队列。

Condition条件变量

ArrayBlockingQueue还使用了java.util.concurrent.locks.Condition条件变量来实现线程间的协作。Condition变量提供了类似Object类中的waitnotifynotifyAll方法,但更强大和灵活。通过Condition变量,可以让线程在特定条件下等待或被唤醒,这对于实现阻塞操作非常重要。

ArrayBlockingQueue中,通常会有两个Condition变量:

  • notFull:表示队列未满的条件。当队列已满时,试图执行插入操作的线程会在这个条件上等待,直到有空间可用。
  • notEmpty:表示队列不为空的条件。当队列为空时,试图执行移除操作的线程会在这个条件上等待,直到有元素可用。

线程安全机制的实现

以下是ArrayBlockingQueue实现线程安全的几个关键点:

  1. 加锁与解锁

    在每次修改队列状态(如插入或删除元素)之前,ArrayBlockingQueue都会先获取主锁,以确保只有一个线程能够进行修改操作。当操作完成后,再释放锁。

    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        // 修改队列状态
    } finally {
        lock.unlock();
    }
    
  2. 等待和通知

    使用Condition变量来处理队列满和空的情况。当队列已满时,插入操作会调用notFull.await()进入等待状态,直到有空间可用。同样,当队列为空时,移除操作会调用notEmpty.await()进入等待状态,直到有新元素被插入。

    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        while (count == items.length) {
            notFull.await();
        }
        // 插入元素
        notEmpty.signal();
    } finally {
        lock.unlock();
    }
    
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        while (count == 0) {
            notEmpty.await();
        }
        // 移除元素
        notFull.signal();
    } finally {
        lock.unlock();
    }
    

完整示例代码

以下是ArrayBlockingQueue的一个简化示例,展示了如何使用ReentrantLock和Condition来实现线程安全的阻塞队列:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class SimpleArrayBlockingQueue<E> {
    private final E[] items;
    private int putIndex, takeIndex, count;
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();

    public SimpleArrayBlockingQueue(int capacity) {
        items = (E[]) new Object[capacity];
    }

    public void put(E e) throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            while (count == items.length) {
                notFull.await();
            }
            items[putIndex] = e;
            if (++putIndex == items.length) putIndex = 0;
            count++;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            while (count == 0) {
                notEmpty.await();
            }
            E e = items[takeIndex];
            if (++takeIndex == items.length) takeIndex = 0;
            count--;
            notFull.signal();
            return e;
        } finally {
            lock.unlock();
        }
    }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/713542.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

北京人工智能数据运营平台发布,并开源大规模数据集

6月14日&#xff0c;AI行业顶级盛会2024北京智源大会正式拉开帷幕。作为大会的重要组成部分&#xff0c;智源大会“人工智能数据新基建”论坛同步召开。本论坛由北京智源人工智能研究院主办&#xff0c;中国互联网协会人工智能工委会和中国移动研究院承办。本次论坛邀请到来自中…

2-5 基于matlab的信号的希尔伯特-黄变换

基于matlab的信号的希尔伯特-黄变换&#xff0c;IMF分解&#xff0c;对IMF进行Hilbert处理&#xff0c;绘制二维/三维时-频图&#xff0c;时间-能量图(瞬时能量谱) &#xff0c;频率-能量图&#xff08;希尔伯特谱&#xff09;。程序已调通&#xff0c;可直接运行。 2-5 希尔伯…

java Springboot网上音乐商城(源码+sql+论文)

1.1 研究目的和意义 随着市场经济发展&#xff0c;尤其是我国加入WTO &#xff0c;融入经济全球化潮流&#xff0c;已进入国内外市场经济发展新时期&#xff0c;音乐与市场联系越来越紧密&#xff0c;我国音乐和网上业务也进入新历史发展阶段。为了更好地服务于市场&#xff0…

11.泛型、trait和生命周期(上)

标题 一、泛型数据的引入二、改写为泛型函数三、结构体/枚举中的泛型定义四、方法定义中的泛型 一、泛型数据的引入 下面是两个函数&#xff0c;分别用来取得整型和符号型vector中的最大值 use std::fs::File;fn get_max_float_value_from_vector(src: &[f64]) -> f64…

.net8 blazor auto模式很爽(五)读取sqlite并显示(2)

在BlazorApp1增加文件夹data&#xff0c;里面增加类dbcont using SharedLibrary.Models; using System.Collections.Generic; using Microsoft.EntityFrameworkCore;namespace BlazorApp1.data {public class dbcont : DbContext{public dbcont(DbContextOptions<dbcont>…

Python进阶:从函数到文件的编程艺术!!!

第二章&#xff1a;Python进阶 模块概述 函数是一段可重复使用的代码块&#xff0c;它接受输入参数并返回一个结果。函数可以用于执行特定的任务、计算结果、修改数据等&#xff0c;使得代码更具模块化和可重用性。 模块是一组相关函数、类和变量的集合&#xff0c;它们被封…

vs+qt5.0 使用poppler 操作库

Poppler 是一个用来生成 PDF 的C类库&#xff0c;从xpdf 继承而来。vs编译库如下&#xff1a; vs中只需要添加依赖库即可 头文件&#xff1a;

2.2 抽头

目录 为什么要抽头 什么是抽头 接入系数 怎么抽头 信号源端抽头 负载端抽头 例题分析 要点总结 为什么要抽头 阻抗转换&#xff0c;使信号源内阻Rs与负载电阻RL变得很大&#xff0c;分流小&#xff0c;再使用并联方式。 什么是抽头 接入系数 电容越大&#xff0c;分压越…

初识PHP

一、格式 每行以分号结尾 <?phpecho hello; ?>二、echo函数和print函数 作用&#xff1a;两个函数都是输出内容到页面中&#xff0c;多用于代码调试。 <?php echo "<h1 styletext-align: center;>test</h1>"; print "<h1 stylet…

使用python绘制三维曲线图

使用python绘制三维曲线图 三维曲线图定义特点 效果代码 三维曲线图 三维曲线图&#xff08;3D曲线图&#xff09;是一种用于可视化三维数据的图表&#xff0c;它展示了数据在三个维度&#xff08;X、Y、Z&#xff09;上的变化。 定义 三维曲线图通过在三维坐标系中绘制曲线…

AI大模型技术揭秘-参数,Token,上下文和温度

深入理解 AI 大模型:参数、Token、上下文窗口、上下文长度和温度 人工智能技术的飞速发展使AI大模型大放异彩,其中涉及的“参数”、“Token”、“上下文窗口”、“上下文长度”及“温度”等专业术语备受瞩目。这些术语背后究竟蕴含何意?它们如何影响AI大模型的性能?一起揭开…

htb_Freelancer

端口扫描 80 88 389 445 扫描ldap协议相关漏洞&#xff0c;没有发现 扫描子域名&#xff0c;加入/etc/hosts&#xff08;后面发现没用&#xff09; 枚举域用户 目录扫描&#xff0c;发现一个/admin目录 访问后发现要账号密码 访问80端口&#xff0c;注册一个freelancer用…

关于二分法的理解(以JS为例)

算法介绍 基本概念 二分查找算法&#xff0c;又称折半查找算法&#xff0c;是一种在有序数组中查找特定元素的高效方法。它的核心思想是将数组分成两半&#xff0c;然后根据目标值与中间元素的比较结果来决定是继续在左半部分还是右半部分进行搜索。 工作原理 初始化&#…

Vue3+Vite报错:vite忽略.vue扩展名 Failed to resolve import ..... Does the file exist?

Vue3Vite报错&#xff1a;vite忽略.vue扩展名 Failed to resolve import … Does the file exist? 先看报错&#xff1a; 分析原因 原因是我们没有写后缀名 建议你在你的vite.config.js中加上如下配置 import { defineConfig } from "vite"; import vue from &qu…

股指期货功能

其金融期货的本质&#xff0c;决定了股指期货具有以下几方面特点&#xff1a; &#xff08;1&#xff09;交割方式为现金交割&#xff1b; &#xff08;2&#xff09;股指期货的持有成本较低&#xff1b; &#xff08;3&#xff09;股指期货的保证金率较低&#xff0c;杠杆性…

R 初级教程之一

IT的发展目前已经相当的内卷&#xff0c;到处都在说24年是将来4年最难的一年&#xff01;确实是&#xff0c;眼下各大厂商都在疯狂的裁员砍掉不营利的业务&#xff0c;收紧业务&#xff0c;不再盲目的扩张。小公司更是水深火热&#xff0c;无以言表。近期有个医院联系让使用R给…

Zombie Animations Set

僵尸动画合集,包括成对攻击/抓取、各种移动方式、爬行、击中反应、死亡动画等。 生产说明 动画总数:99(包括22个位置变化) 配对动画:36 攻击次数:6次 爬网:9 命中反应:6 空转:14 行程2 跑步次数:9次 短跑:2 匝数:3 步行次数:12次 免责声明 任何游戏玩法蓝图都不包…

【计算机毕业设计】240基于微信小程序的校园综合服务平台

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

禁止methtype联网

mathtype断网_如何禁止mathtype联网-CSDN博客https://blog.csdn.net/qq_41060221/article/details/128144783

StarNet实战:使用StarNet实现图像分类任务(二)

文章目录 训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整策略设置混合精度&#xff0c;DP多卡&#xff0c;EMA定义训练和验证函数训练函数验证函数调用训练和验证方法 运行以及结果查看测试完整的代码 在上…