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

Java wait/notify 經典範例:駕駛與乘客協作模擬

     編輯:J2EE

前言

Object.wait()、notify()、notifyAll() 是 Java 線程協作的基礎原語,必須在 synchronized 區塊/方法中調用。本範例模擬「駕駛等待乘客、乘客上車通知駕駛」場景,展示基本同步協作流程。

程式碼結構


public class Road {
    public static void main(String[] args) {
        Car car = new Car();
        new Thread(new Driver(car)).start();
        new Thread(new Passenger(car)).start();
    }
}

class Car {
    synchronized public void waitForPassenger() {
        try { wait(); } catch (InterruptedException e) {}
    }
    synchronized public void passengerArrived() {
        notify(); // 喚醒單一等待線程 (此處只有駕駛)
    }
}

class Driver implements Runnable {
    private Car car;
    public Driver(Car c) { this.car = c; }
    public void run() {
        while (true) {
            System.out.println("駕駛等待乘客......");
            car.waitForPassenger(); // 釋放鎖進入 WAITING
            try { Thread.sleep(3000); } catch (InterruptedException e) {}
            Thread.yield();
            try { Thread.sleep(100); } catch (InterruptedException e) {}
            car.passengerArrived(); // 模擬駕駛完成行程後通知下一輪? (邏輯略顯混淆)
            System.out.println("乘客上車,駕駛出發");
        }
    }
}

class Passenger implements Runnable {
    private Car car;
    public Passenger(Car c) { this.car = c; }
    public void run() {
        while (true) {
            Thread.yield();
            try { Thread.sleep(3000); } catch (InterruptedException e) {}
            System.out.println("一位乘客上車");
            car.passengerArrived(); // 通知駕駛
            System.out.println("駕駛停止等待,進入休眠...");
            car.waitForPassenger(); // 乘客也進入等待? (邏輯混淆)
        }
    }
}

關鍵點解析

  • 同步前提:wait/notify 必須在同一物件鎖 (Car 實例) 的 synchronized 方法中調用。
  • wait():釋放鎖,線程進入 WAITING 狀態,直到被 notify/notifyAll 喚醒或中斷。
  • notify():喚醒單一在該鎖上等待的線程 (若多個則任選一);喚醒後需重新獲得鎖才能繼續執行。
  • notifyAll():喚醒所有等待線程,避免「信號丟失」導致部分餓死。

範例邏輯缺陷與改進

原範例中駕駛與乘客雙方都呼叫 wait/notify,職責不清,易產生活鎖或邏輯混淆。標準生產者-消費者模型應為:


class Car {
    private boolean hasPassenger = false;
    synchronized public void waitForPassenger() {
        while (!hasPassenger) { try { wait(); } catch (InterruptedException e) {} }
        hasPassenger = false; // 乘客已上車,重置狀態
    }
    synchronized public void passengerArrived() {
        hasPassenger = true;
        notify(); // 或 notifyAll()
    }
}
// Driver 呼叫 waitForPassenger() 循環載客
// Passenger 呼叫 passengerArrived() 送客

最佳實務建議

  1. 優先使用 java.util.concurrent 高層組件 (BlockingQueue、Semaphore、CountDownLatch、CyclicBarrier、Lock/Condition) 替代底層 wait/notify。
  2. wait() 必須放在 while (condition) 循環中,防止虛假喚醒。
  3. 使用 notifyAll() 除非確定單一等待者且效能極度敏感。
  4. 同步區塊盡量精簡,避免在鎖內執行耗時操作 (I/O、sleep)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved