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

Java Condition 實現生產者消費者模式:比 Object.wait/notify 更安全高效

     編輯:Java 綜合教學

Java Condition 詳解:生產者消費者模式最佳實踐

java.util.concurrent.locks.Condition 是 JDK 1.5 引入的線程協作工具,配合 Lock 使用,提供 await()/signal()/signalAll(),功能對標 Object.wait/notify/notifyAll 但更安全、更靈活、支持多條件隊列。本文對比兩者,給出生產消費完整實現。

Object.wait/notify vs Condition 對比

特性Object MonitorCondition
綁定鎖隱式 this / synchronized 鎖顯式 Lock 實例(可多條件共享一把鎖)
等待方法wait()await() / awaitUninterruptibly() / awaitNanos()
喚醒方法notify() / notifyAll()signal() / signalAll()
多條件隊列不支持(單一等待集)支持(一把鎖創建多個 Condition)
可中斷等待不支持支持 await() 拋 InterruptedException
公平性非公平可配合 ReentrantLock(true) 實現公平
檢查鎖狀態無必须在 lock.lock() 與 unlock() 之間調用

生產消費者完整實現(環形緩衝區)

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionDemo {
    private final Object[] queue = new Object[100];
    private int readIndex = 0, writeIndex = 0, dataLen = 0;
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();  // 生產者等待條件
    private final Condition notEmpty = lock.newCondition(); // 消費者等待條件

    // 生產
    public void write(Object obj) {
        lock.lock();
        try {
            while (dataLen >= queue.length) { // 用 while 防虛假喚醒
                System.out.println("隊列滿,生產者等待...");
                notFull.await();
            }
            queue[writeIndex] = obj;
            writeIndex = (writeIndex + 1) % queue.length;
            dataLen++;
            notEmpty.signal(); // 喚醒一個消費者
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }

    // 消費
    public Object read() {
        lock.lock();
        try {
            while (dataLen <= 0) {
                System.out.println("隊列空,消費者等待...");
                notEmpty.await();
            }
            Object obj = queue[readIndex];
            readIndex = (readIndex + 1) % queue.length;
            dataLen--;
            notFull.signal(); // 喚醒一個生產者
            return obj;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return null;
        } finally {
            lock.unlock();
        }
    }

    // 測試
    public static void main(String[] args) {
        final ConditionDemo demo = new ConditionDemo();
        new Thread(() -> {
            for (int i = 0; i < 1000; i++) demo.write(i);
        }, "Producer").start();
        new Thread(() -> {
            while (true) {
                Object obj = demo.read();
                if (obj != null) System.out.println("消費: " + obj);
            }
        }, "Consumer").start();
    }
}

關鍵最佳實踐

  1. while 循環檢查條件:while (condition) await() 防止虛假喚醒(JVM 規範允許無通知喚醒)。
  2. signal vs signalAll:單生產單消費用 signal();多生產/多消費建議 signalAll() 避免信號丟失導致線程饑餓。
  3. Lock 必須成對:lock.lock() → try → finally lock.unlock(),否則死鎖。
  4. 異常處理:await() 拋 InterruptedException 時需恢復中斷狀態 Thread.currentThread().interrupt()。

應用場景擴展

  • 線程池任務隊列(ArrayBlockingQueue 內部即用 Condition)。
  • 讀寫鎖實現(ReentrantReadWriteLock 內部有读/写 Condition)。
  • 定時任務調度器(DelayQueue 使用 Condition 等待最近任務到期)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved