【Java并发】【ArrayBlockingQueue】适合初学体质的ArrayBlockingQueue入门

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD

🔥 2025本人正在沉淀中... 博客更新速度++

👍 欢迎点赞、收藏、关注,跟上我的更新节奏

📚欢迎订阅专栏,专栏名《在2B工作中寻求并发是否搞错了什么》

什么是ArrayBlockingQueue

ArrayBlockingQueue是 Java 并发编程中一个基于数组实现的有界阻塞队列,属于 java.util.concurrent 包,实现了 BlockingQueue 接口。

具有以下特性:

有界性

  • 队列容量在创建时固定,无法动态扩容(必须显式指定初始容量)。
  • 适合需要控制资源使用的场景,避免无限制增长导致内存溢出。

线程安全

  • 内部通过 ReentrantLock 保证并发操作的安全性。
  • 采用"单锁双条件"(一个锁管理入队和出队条件)实现同步。

阻塞操作

  • 队列满时:put(e) 方法会阻塞,直到有空间可用。
  • 队列空时:take() 方法会阻塞,直到有新元素加入。

FIFO 原则

  • 元素按先进先出顺序处理,保证公平性。

使用ArrayBlockingQueue

构造方法

java 复制代码
// 指定容量(必须)
ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);

// 指定容量和公平性(true 表示公平锁)
ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10, true);

// 指定容量、公平性,并初始化集合
List<Integer> list = Arrays.asList(1, 2, 3);
ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10, true, list);

阻塞使用(put、take)

put(E e)方法: 阻塞当前线程生产(往队列中塞数据)

java 复制代码
// 生产者线程
new Thread(() -> {
    try {
        for (int i = 0; i < 5; i++) {
            queue.put(i); // 队列满时阻塞
            System.out.println("生产: " + i);
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}).start();

take()方法: 阻塞当前线程消费(往队列里面取数据)。

java 复制代码
// 消费者线程
new Thread(() -> {
    try {
        while (true) {
            Integer value = queue.take(); // 队列空时阻塞
            System.out.println("消费: " + value);
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}).start();

非阻塞方法使用(offer、poll)

offer(E e)方法:尝试插入,队列满时直接返回 false。

java 复制代码
boolean success = queue.offer(100);
System.out.println("插入是否成功: " + success); 

poll()方法:尝试取出,队列空时返回 null。

java 复制代码
Integer value = queue.poll();
System.out.println("取出值: " + value);

不建议使用的非阻塞方法(add、remove、element)

add和element这种方法,会直接抛出异常。

add(E e): 向阻塞队列放入元素,阻塞队列满的话,直接抛出IllegalStateException异常。

java 复制代码
ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(1); // 容量为1

queue.add(10); // 成功插入
try {
    queue.add(20); // 队列已满,抛出 IllegalStateException
} catch (IllegalStateException e) {
    System.out.println("队列已满,add() 抛异常: " + e);
}

// AbstractQueue#add
// 抛出IllegalStateException异常
public boolean add(E e) {
    if (offer(e))
        return true;
    else
        throw new IllegalStateException("Queue full");	// 阻塞队满,抛出异常
}

elemet(): 向阻塞队列获取元素,阻塞队列为空的话,直接抛出NoSuchElementException异常。

java 复制代码
ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(1); // 空队列

try {
    Integer head = queue.element(); // 队列为空,抛出 NoSuchElementException
} catch (NoSuchElementException e) {
    System.out.println("队列为空,element() 抛异常: " + e);
}

// AbstractQueue#element
public E element() {
    E x = peek();
    if (x != null)
        return x;
    else
        throw new NoSuchElementException(); // 阻塞队列为空,抛出异常
}

remove(): 删除阻塞队列的头元素,并返回这个头元素。如果阻塞队列为空,直接抛出NoSuchElementException异常。

java 复制代码
ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(1); // 空队列
queue.remove();	// NoSuchElementException异常

public E remove() {
    E x = poll();
    if (x != null)
        return x;
    else
        throw new NoSuchElementException();	// 阻塞队列为空,抛出异常
}

超时阻塞使用(offer、poll)

也是offer方法,只是多传了时间相关的参数。

offer(e, time, unit): 等待time秒后,插入数据,返回执行结果。

java 复制代码
// 生产者等待2秒插入
boolean success = queue.offer(200, 2, TimeUnit.SECONDS);

poll(time, unit) :等待time秒后获取数据,队列为空的话,返回null。

java 复制代码
// 消费者等待3秒取出
Integer value = queue.poll(3, TimeUnit.SECONDS);

后话

主播这么快又结束了?没有的!宝子,还有呢!

关注点给主播点上,下一篇主播给大家表演看源码。

相关推荐
惊鸿一博3 分钟前
java_api路径_@Parameter与@RequestParam区别
java·python
异常君4 分钟前
Java 虚拟线程技术详解:原理、实践与优化(下)
java
啃瓜子的松鼠12 分钟前
泛微OAe9-自定义资源看板
java·后端·sql
异常君15 分钟前
Java 虚拟线程技术详解:原理、实践与优化(上)
java
cainiao08060519 分钟前
Java 大视界——Java大数据在智能安防视频监控中的异常事件快速响应与处理机制
java
爬菜29 分钟前
java事件处理机制
java
coding随想31 分钟前
从图书馆到无序仓库:操作系统如何高效管理你的文件
后端
王中阳Go40 分钟前
2025Java面试八股②(含121道面试题和答案)
java·后端·面试
neoooo40 分钟前
🎯 深入理解:JOIN 中 ON vs WHERE 条件差异
java·后端·mysql
boy快快长大1 小时前
【线程与线程池】线程数设置(四)
java·开发语言