首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

手把手教你實現 Java 隊列類:基於 Vector 的線程安全封裝

     編輯:Java 程式設計入門

前言:為什麼要手寫 Queue?

Java Collections Framework 自 1.5 版起提供了 java.util.Queue 介面及 LinkedList、ArrayDeque、PriorityQueue、ConcurrentLinkedQueue 等豐富實作。但在教學、面試、或受限於舊版 JDK (1.4 以前) 環境時,理解如何基於基礎集合類 (如 Vector) 封裝線程安全隊列,極有助於掌握**集合封裝、同步控制、異常設計、介面導向程式設計**等核心功力。

需求分析:隊列核心操作契約

操作語義異常行為
enq(E element)尾部插入元素 (入隊)容量受限時拋出 IllegalStateException (本範例 Vector 自動擴容,故不拋出)
deq()移除並返回頭部元素 (出隊)隊列為空拋出 EmptyQueueException (自訂檢查型異常)
front()查看但不移除頭部元素隊列為空拋出 EmptyQueueException
empty()判斷是否為空返回 boolean
clear()清空隊列無返回值
search(Object o)查找元素距隊頭位置 (0-based)不存在返回 -1

設計決策

  • 底層容器:Vector — 線程安全、動態陣列、支援索引存取、JDK 1.0 即存在。
  • 繼承關係:extends Vector (繼承實作) 或 **組合** (持有 Vector 私有欄位) —— **強烈建議組合**,避免暴露 Vector 所有 public 方法 (如 addElementAt, setElementAt) 破壞隊列語義。本範例為教學演示採用繼承,實務請改組合。
  • 同步粒度:方法級 synchronized (繼承自 Vector 方法已同步,但複合操作需額外同步)。
  • 異常體系:自訂 EmptyQueueException extends Exception (檢查型異常),強制調用者處理空隊列情況。

完整實作代碼 (JDK 1.1+ 兼容)

import java.util.Vector;

/**
 * 自訂空隊列異常 (檢查型異常)
 */
class EmptyQueueException extends Exception {
    public EmptyQueueException() {
        super("Queue is empty");
    }
    public EmptyQueueException(String message) {
        super(message);
    }
}

/**
 * 基於 Vector 的線程安全隊列實作 (教學示範版,生產環境請用 java.util.Queue 實作)
 */
public class Queue extends Vector { // JDK 1.5+ 建議改為 Queue extends AbstractQueue 並組合 Vector

    /**
     * 入隊:尾部插入
     * @param x 待插入元素
     */
    public synchronized void enq(Object x) {
        super.addElement(x); // Vector 內部已同步,但為了複合操作原子性,方法級同步無害
    }

    /**
     * 出隊:移除並返回頭部元素
     * @return 隊頭元素
     * @throws EmptyQueueException 隊列為空
     */
    public synchronized Object deq() throws EmptyQueueException {
        if (this.empty()) {
            throw new EmptyQueueException("Cannot dequeue from empty queue");
        }
        Object head = super.elementAt(0);
        super.removeElementAt(0);
        return head;
    }

    /**
     * 查看隊頭元素 (不移除)
     * @return 隊頭元素
     * @throws EmptyQueueException 隊列為空
     */
    public synchronized Object front() throws EmptyQueueException {
        if (this.empty()) {
            throw new EmptyQueueException("Queue is empty");
        }
        return super.elementAt(0);
    }

    /**
     * 判斷隊列是否為空
     * @return true 如果隊列無元素
     */
    public boolean empty() {
        return super.isEmpty();
    }

    /**
     * 清空隊列
     */
    public synchronized void clear() {
        super.removeAllElements();
    }

    /**
     * 查找元素首次出現位置 (距隊頭索引)
     * @param x 待查找元素
     * @return 索引 (0-based),不存在返回 -1
     */
    public int search(Object x) {
        return super.indexOf(x); // Vector.indexOf 返回首次出現索引
    }

    // 測試主程式
    public static void main(String[] args) {
        Queue q = new Queue();
        q.enq("A");
        q.enq("B");
        q.enq("C");
        System.out.println("Front: " + q.front()); // A
        System.out.println("Search B: " + q.search("B")); // 1
        try {
            System.out.println("Deq: " + q.deq()); // A
            System.out.println("Deq: " + q.deq()); // B
            System.out.println("Deq: " + q.deq()); // C
            System.out.println("Deq: " + q.deq()); // 拋出異常
        } catch (EmptyQueueException e) {
            System.err.println("Caught: " + e.getMessage());
        }
    }
}


現代化改良指南 (JDK 8+)

  1. 使用介面導向:public class ArrayQueue implements Queue。
  2. 組合而非繼承:private final List data = new ArrayList<>(); (單執行緒) 或 new CopyOnWriteArrayList<>() / Collections.synchronizedList (多執行緒)。
  3. 泛型化:移除 Object 強轉,編譯期類型安全。
  4. 異常選擇:deq() 拋 NoSuchElementException (非檢查型,符合 JDK Queue 規約),或提供 poll() 返回 null。
  5. 利用現有實作:new ArrayDeque<>() (非執行緒安全、高效)、new ConcurrentLinkedQueue<>() (無鎖、高併發)、new LinkedBlockingQueue<>() (阻塞、生產消費者)。

結語

手寫隊列不是為了造輪子,而是為了**理解輪子的內部結構**。掌握封裝、同步、異常、介面設計原則,才能在面對並發編程、框架原理分析、效能調優時游刃有餘。**生產代碼請直接使用 JDK 提供的成熟 Queue 實作。**

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved