You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java有界阻塞队列实现疑问:为何无需额外互斥锁?

关于LeetCode 1188用Semaphore实现有界阻塞队列的线程安全问题

你提到的这种仅用empty和full两个信号量、不加互斥锁直接用非线程安全的ArrayDeque的解法,实际上存在线程安全隐患,并不是严格正确的实现,只是可能通过了LeetCode的基础测试用例。

问题核心

ArrayDeque本身不是线程安全的,它的addLast、removeFirst等方法没有任何同步控制:

  • 内部的head和tail指针是普通int变量,不是volatile的,多线程下无法保证可见性;
  • 当多个线程同时执行addLast时,可能出现tail指针更新丢失、数组元素被覆盖的情况,直接破坏队列结构;
  • 同理,多个线程同时执行removeFirst也会导致head指针的混乱,引发元素丢失或重复取出的问题。

为什么你会觉得它“正确”?

LeetCode的测试用例可能只覆盖了阻塞逻辑验证:比如队列满时enqueue会阻塞,队列空时dequeue会阻塞,但没有构造真正的高并发修改场景(比如多个线程同时执行enqueue或dequeue),所以这种有隐患的解法能通过测试。

正确的Semaphore实现方式

要让基于ArrayDeque的实现真正线程安全,必须额外加一个互斥信号量(比如mutex,初始许可数为1),用来保护队列的所有修改和查询操作:

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.Semaphore;

public class BoundedBlockingQueue {
    private final Semaphore empty;
    private final Semaphore full;
    private final Semaphore mutex;
    private final Deque<Integer> queue;

    public BoundedBlockingQueue(int capacity) {
        // 控制可用空位数量,初始为队列容量
        empty = new Semaphore(capacity);
        // 控制可用元素数量,初始为0
        full = new Semaphore(0);
        // 保证同一时刻只有一个线程能修改队列
        mutex = new Semaphore(1);
        queue = new ArrayDeque<>();
    }

    public void enqueue(int element) throws InterruptedException {
        empty.acquire(); // 等待直到有空位
        mutex.acquire(); // 独占队列的修改权限
        queue.addLast(element);
        mutex.release();
        full.release(); // 增加一个可用元素
    }

    public int dequeue() throws InterruptedException {
        full.acquire(); // 等待直到有元素
        mutex.acquire();
        int element = queue.removeFirst();
        mutex.release();
        empty.release(); // 增加一个可用空位
        return element;
    }

    public int size() {
        int size = 0;
        try {
            mutex.acquire();
            size = queue.size();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            mutex.release();
        }
        return size;
    }
}

这里的mutex信号量保证了所有对ArrayDeque的操作都是互斥的,结合empty和full的边界控制,才是符合线程安全要求的实现。

内容的提问来源于stack exchange,提问作者curiousengineer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 11:27:43