隊列是計算機科學中最基礎的數據結構之一,廣泛應用於任務調度、消息中間件、線程池、流量控制等核心場景。本文從底層原理出發,手寫實現基於數組的環形隊列,並延伸至 Java 集合框架與並發隊列的工程化應用。
使用固定大小數組 + 兩個指針(head/tail)+ 元素計數器,實現 O(1) 入隊出隊。
public class ArrayQueue<E> {
private final Object[] elements;
private int head = 0; // 隊頭索引
private int tail = 0; // 隊尾索引(指向下一個插入位置)
private int size = 0; // 當前元素數量
@SuppressWarnings("unchecked")
public ArrayQueue(int capacity) {
if (capacity < 1) throw new IllegalArgumentException("Capacity must be >= 1");
this.elements = new Object[capacity];
}
/** 入隊:尾部插入,尾指針環形前進 */
public boolean offer(E e) {
if (isFull()) return false; // 或拋出異常
elements[tail] = e;
tail = (tail + 1) % elements.length;
size++;
return true;
}
/** 出隊:頭部取出,頭指針環形前進 */
@SuppressWarnings("unchecked")
public E poll() {
if (isEmpty()) return null; // 或拋出異常
E e = (E) elements[head];
elements[head] = null; // 幫助 GC
head = (head + 1) % elements.length;
size--;
return e;
}
/** 查看隊頭元素不移除 */
@SuppressWarnings("unchecked")
public E peek() {
return isEmpty() ? null : (E) elements[head];
}
public boolean isEmpty() { return size == 0; }
public boolean isFull() { return size == elements.length; }
public int size() { return size; }
public int capacity() { return elements.length; }
}
(index + 1) % capacity 實現指針循環,避免數據搬移Object[],取出時強制轉型並 @SuppressWarningsCollection
└── Queue
├── Deque (雙端隊列)
│ ├── ArrayDeque (數組雙端隊列,非線程安全)
│ └── LinkedList (鏈表實現,亦實現 List)
├── PriorityQueue (優先級隊列,堆實現)
└── BlockingQueue (阻塞隊列接口,並發包核心)
├── ArrayBlockingQueue (有界數組隊列)
├── LinkedBlockingQueue (可選有界鏈表隊列)
├── PriorityBlockingQueue (優先級阻塞隊列)
├── DelayQueue (延遲隊列)
├── SynchronousQueue (同步移交隊列,容量 0)
└── LinkedTransferQueue (傳輸隊列)
| 隊列 | 底層結構 | 有界性 | 線程安全 | 順序性 | 典型場景 |
|---|---|---|---|---|---|
| ArrayDeque | 環形數組 | 無界(擴容) | ❌ | FIFO/LIFO | 單線程棧/隊列、鏈表替代 |
| PriorityQueue | 最小堆 | 無界 | ❌ | 優先級序 | 任務調度、Dijkstra、Huffman |
| ArrayBlockingQueue | 環形數組+ReentrantLock | 有界 | ✅ | FIFO | 生產消費、線程池工作隊列 |
| LinkedBlockingQueue | 鏈表+雙鎖 | 可選有界 | ✅ | FIFO | 高吞吐生產消費、Executors 默認 |
| ConcurrentLinkedQueue | 鏈表+CAS | 無界 | ✅(無鎖) | FIFO | 高併發非阻塞場景 |
BlockingQueue 提供阻塞語義:
put(e):隊列滿時阻塞等待take():隊列空時阻塞等待offer(e, timeout) / poll(timeout):帶超時控制public class ProducerConsumerDemo {
private static final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
private static final Random random = new Random();
public static void main(String[] args) {
// 生產者
new Thread(() -> {
try {
while (true) {
int num = random.nextInt(100);
queue.put(num);
System.out.printf("[生產] %d | 隊列大小: %d%n", num, queue.size());
Thread.sleep(random.nextInt(500));
}
} catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}, "Producer").start();
// 消費者
new Thread(() -> {
try {
while (true) {
int num = queue.take();
System.out.printf("[消費] %d | 隊列大小: %d%n", num, queue.size());
Thread.sleep(random.nextInt(800));
}
} catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}, "Consumer").start();
}
}
ThreadPoolExecutor 核心參數 workQueue 直接決定拒絕策略與吞吐特性Logback AsyncAppender 內部使用 ArrayBlockingQueue 解耦業務線程與 I/O 線程DelayQueue 存放令牌過期時間,實現平滑限流LinkedBlockingQueue + 消費者線程組,實現進程內事件異步分發ScheduledExecutorService 內部使用 DelayedWorkQueue(優先隊列變體)管理定時任務drainTo()、addAll() 減少鎖競爭/上下文切換ConcurrentLinkedQueue 或 Disruptor隊列作為「緩衝」與「解耦」的核心數據結構,其環形數組實現體現了空間複用的智慧,而 Java 並發包中的阻塞隊列更將同步原語內化為 API,極大簡化了多線程協作編程。掌握從手寫實現到框架選型的完整鏈路,是構建高性能並發系統的必修課。