【面试题精讲】ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别?

有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top

首发博客地址

面试题手册

系列文章地址


1. 什么是ArrayBlockingQueue和LinkedBlockingQueue?

  • ArrayBlockingQueue:是一个基于数组实现的有界阻塞队列,它按照先进先出(FIFO)的原则对元素进行排序。
  • LinkedBlockingQueue:是一个基于链表实现的可选有界或无界阻塞队列,它也按照先进先出(FIFO)的原则对元素进行排序。

2. 为什么需要ArrayBlockingQueue和LinkedBlockingQueue?

在多线程编程中,我们经常需要使用队列来实现线程间的数据共享。而阻塞队列是一种特殊的队列,当队列为空时,从队列中获取元素的操作会被阻塞;当队列满时,往队列中添加元素的操作会被阻塞。这样可以有效地控制线程之间的协作和同步。

ArrayBlockingQueue和LinkedBlockingQueue都是Java并发包提供的线程安全的阻塞队列实现,它们提供了不同的特性和适用场景。

3. ArrayBlockingQueue和LinkedBlockingQueue的实现原理?

ArrayBlockingQueue

  • ArrayBlockingQueue内部使用一个定长数组来存储元素,通过两个指针分别指向队头和队尾。
  • 当往队列中添加元素时,如果队列已满,则添加操作会被阻塞,直到有空闲位置。
  • 当从队列中获取元素时,如果队列为空,则获取操作会被阻塞,直到有可用元素。
  • ArrayBlockingQueue使用ReentrantLock来保证线程安全,并通过Condition实现阻塞和唤醒机制。

LinkedBlockingQueue

  • LinkedBlockingQueue内部使用一个链表来存储元素,每个节点包含一个元素和指向下一个节点的引用。
  • 当往队列中添加元素时,如果队列已满(对于有界队列),则添加操作会被阻塞,直到有空闲位置。
  • 当从队列中获取元素时,如果队列为空,则获取操作会被阻塞,直到有可用元素。
  • LinkedBlockingQueue使用两把锁分别控制队头和队尾的访问,以提高并发性能。

4. ArrayBlockingQueue和LinkedBlockingQueue的使用示例

ArrayBlockingQueue示例:

arduino 复制代码
 
import java.util.concurrent.ArrayBlockingQueue;

public class ArrayBlockingQueueExample {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个容量为3的ArrayBlockingQueue
        ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);

        // 往队列中添加元素
        queue.put(1);
        queue.put(2);
        queue.put(3);

        // 队列已满,添加操作会被阻塞
        queue.put(4);

        // 从队列中获取元素
        int element = queue.take();
        System.out.println("取出元素:" + element);

        // 队列已空,获取操作会被阻塞
        int element2 = queue.take();
    }
}

LinkedBlockingQueue示例:

arduino 复制代码
 
import java.util.concurrent.LinkedBlockingQueue;

public class LinkedBlockingQueueExample {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个容量为3的LinkedBlockingQueue
        LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(3);

        // 往队列中添加元素
        queue.put(1);
        queue.put(2);
        queue.put(3);

        // 队列已满,添加操作会被阻塞
        queue.put(4);

        // 从队列中获取元素
        int element = queue.take();
        System.out.println("取出元素:" + element);

        // 队列已空,获取操作会被阻塞
        int element2 = queue.take();
    }
}

5. ArrayBlockingQueue和LinkedBlockingQueue的优点

  • ArrayBlockingQueue:

    • 内部使用数组实现,读写性能较高。
    • 支持有界队列,可以限制队列的大小。
  • LinkedBlockingQueue:

    • 内部使用链表实现,插入和删除性能较高。
    • 支持可选的有界或无界队列。

6. ArrayBlockingQueue和LinkedBlockingQueue的缺点

  • ArrayBlockingQueue:

    • 容量固定,不支持动态扩容。
    • 在并发情况下,可能存在线程饥饿问题(某些线程一直无法获取到锁)。
  • LinkedBlockingQueue:

    • 内存消耗较大,因为每个节点都需要额外的空间来存储引用。
    • 在并发情况下,可能存在线程饥饿问题(某些线程一直无法获取到锁)。

7. ArrayBlockingQueue和LinkedBlockingQueue的使用注意事项

  • ArrayBlockingQueue:

    • 需要指定队列的容量大小。
    • 当队列已满时,添加操作会被阻塞。
    • 当队列为空时,获取操作会被阻塞。
  • LinkedBlockingQueue:

    • 可以选择有界或无界队列。
    • 当队列已满时(对于有界队列),添加操作会被阻塞。
    • 当队列为空时,获取操作会被阻塞。

8. 总结

ArrayBlockingQueue和LinkedBlockingQueue是Java并发包提供的线程安全的阻塞队列实现。它们分别基于数组和链表来存储元素,并提供了不同的特性和适用场景。ArrayBlockingQueue适合读写性能较高、固定容量的场景;而LinkedBlockingQueue适合插入和删除性能较高、可选有界或无界的场景。在使用时需要根据具体需求选择合适的队列实现。

相关推荐
devlei17 分钟前
从源码泄露看AI Agent未来:深度对比Claude Code原生实现与OpenClaw开源方案
android·前端·后端
努力的小郑2 小时前
Canal 不难,难的是用好:从接入到治理
后端·mysql·性能优化
Victor3563 小时前
MongoDB(87)如何使用GridFS?
后端
Victor3563 小时前
MongoDB(88)如何进行数据迁移?
后端
小红的布丁3 小时前
单线程 Redis 的高性能之道
redis·后端
GetcharZp3 小时前
Go 语言只能写后端?这款 2D 游戏引擎刷新你的认知!
后端
宁瑶琴4 小时前
COBOL语言的云计算
开发语言·后端·golang
普通网友5 小时前
阿里云国际版服务器,真的是学生党的性价比之选吗?
后端·python·阿里云·flask·云计算
IT_陈寒6 小时前
Vue的这个响应式问题,坑了我整整两小时
前端·人工智能·后端
Soofjan6 小时前
Go 内存回收-GC 源码1-触发与阶段
后端