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

《Thinking in Java》多線程仿真實戰:銀行出納員、飯店點餐、汽車裝配線三大經典模型完整實現

     編輯:Java 綜合教學

前言

《Thinking in Java》第 21 章通過三個豐富的仿真案例,展示了阻塞隊列、線程協作、動態調度等並發核心模式。本文保留原著設計精髓,代碼升級為 Java 8+ 風格,並添加關鍵點註解。


案例一:銀行出納員動態調度系統

業務場景

  • 客戶隨機到達,進入有限隊列排隊。
  • 出納員從隊列取客服務,服務時間不定。
  • 管理器根據「排隊長度/出納員數」比率動態增減出納員,平衡等待時間與資源成本。

核心組件設計

關鍵代碼片段:動態調度邏輯

public void adjustTellerNumber() {
    int ratio = customerLine.size() / workingTellers.size();
    if (ratio > 2) { // 排隊過長 → 增加出納員
        if (!tellersDoingOtherThings.isEmpty()) {
            Teller t = tellersDoingOtherThings.remove();
            t.serveCustomerLine(); // notifyAll 喚醒
            workingTellers.add(t);
        } else {
            Teller t = new Teller(customerLine);
            exec.execute(t);
            workingTellers.add(t);
        }
    } else if (workingTellers.size() > 1 && ratio < 2) { // 閒置過多 → 減少
        reassignOneTeller(); // 移至做其他事隊列
    }
}

運行效果

控制台實時打印隊列狀態與活躍出納員 ID,觀察隨負載自動擴縮容:

[Customer@1, Customer@2...] {T1 T2 T3}
[Customer@5...] {T1 T2}
[] {T1}

案例二:飯店點餐全流程協作

業務流程

  1. 顧客入座 → 侍者分配。
  2. 顧客點餐 → 侍者提交訂單到 orders 隊列。
  3. 廚師從 orders 取單 → 製作 → 成品放入對應侍者的 filledOrders 隊列。
  4. 侍者從 filledOrders 取盤 → 送達顧客 placeSetting(SynchronousQueue)。
  5. 顧客 take() 盤子 → 用餐 → 循環下一道菜。

隊列拓撲:零直接耦合

Customer ──(placeOrder)──▶ WaitPerson ──(orders.put)──▶ Restaurant.orders
Chef ──(orders.take)──▶ Restaurant.orders
Chef ──(filledOrders.put)──▶ WaitPerson.filledOrders
WaitPerson ──(placeSetting.put)──▶ Customer.placeSetting (SynchronousQueue)
Customer ──(placeSetting.take)──▶ 用餐

精妙點:所有線程間零直接調用,完全通過阻塞隊列傳遞消息對象,實現「共享內存」→「通信共享內存」範式轉換。

關鍵類結構

  • Order:攜帶 customer、waitPerson、food 信息的傳遞對象。
  • Plate:成品載體,關聯 Order 以便路由回正確侍者/顧客。
  • SynchronousQueue<Plate>:容量 0,put/take 必須配對,完美模擬「上菜-取菜」同步交接。

案例三:汽車裝配線——CyclicBarrier 同步裝配

流水線階段

  1. ChassisBuilder:生產底盤 → chassisQueue。
  2. Assembler:從 chassisQueue 取底盤 → 雇傭 3 類機器人並行裝配 → CyclicBarrier(4) 等待全部完成 → 放入 finishedQueue。
  3. EngineRobot / DriveTrainRobot / WheelsRobot:實現 performService(),調用 Car.addXxx()。
  4. RobotPool:管理機器人池,hire(Class<? extends Robot>, Assembler) 分配空閒機器人並 engage()。
  5. Reporter:消費 finishedQueue 打印完整車輛信息。
  6. CyclicBarrier 同步機制

    // Assembler 中
    private CyclicBarrier barrier = new CyclicBarrier(4); // 1 Assembler + 3 Robots
    
    // 雇傭機器人
    robotPool.hire(EngineRobot.class, this);
    robotPool.hire(DriveTrainRobot.class, this);
    robotPool.hire(WheelsRobot.class, this);
    
    barrier.await(); // 4 方到齊才繼續,保證單車裝配原子性
    finishedQueue.put(car);

    RobotPool 分配邏輯

    public synchronized void hire(Class<? extends Robot> type, Assembler a) throws Exception {
        for (Robot r : pool) {
            if (r.getClass().equals(type)) {
                pool.remove(r);
                r.assignAssembler(a).engage(); // 關聯組裝線 + 喚醒線程
                return;
            }
        }
        wait(); // 池空則等待歸還
        hire(type, a); // 遞歸重試
    }

    設計亮點

    • 資源池化:機器人復用,避免頻繁創建銷毀。
    • 屏障同步:CyclicBarrier 確保 3 道工序並行且全部完成才流轉下一輛車。
    • 狀態機:Robot 狀態:空閒 → 分配 → 執行 → 屏障等待 → 歸還池 → 掛起。

    三大案例並發模式總結對比

類職責關鍵並發機制
Customer不可變數據類,攜帶 serviceTime無狀態,線程安全
CustomerLine繼承 ArrayBlockingQueue<Customer>有界隊列,生產者/消費者自動阻塞
CustomerGenerator定時 put() 客戶生產者線程
Tellertake() 客戶 → sleep(serviceTime) → 計數消費者線程,synchronized 狀態切換
TellerManager定期掃描隊列/出納員比率,PriorityQueue 按服務數調度調度器線程,wait/notify 控制出納員掛起/恢復

現代化改造建議(Java 21+)

  • 使用 Virtual Threads (Project Loom) 替換平台線程,百萬級客戶/訂單無壓力。
  • 用 Structured Concurrency (JEP 453) 管理線程組生命週期,自動傳播取消/異常。
  • 用 Record 定義 Customer、Order、Plate 等不可變數據載體。
  • 用 Sealed Interface 定義 Robot 類型層級,編譯期保證窮盡匹配。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
模式銀行出納員飯店點餐汽車裝配線
核心協作組件ArrayBlockingQueue + PriorityQueue多層 BlockingQueue (LinkedBlockingQueue, SynchronousQueue)BlockingQueue + CyclicBarrier + 對象池
動態調度✅ TellerManager 根據負載增減線程❌ 固定廚師/侍者數❌ 固定機器人池大小
同步原語wait/notify (Teller 掛起/恢復)隱式 (Queue 阻塞)CyclicBarrier (多方同步)
資源池化❌ 出納員動態創建/銷毀❌✅ RobotPool 復用機器人
擴展性易增減出納員邏輯易增菜品/廚師類型易增裝配工序/機器人類型