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

Java 多線程進階:Condition 條件變量詳解與生產者消費者實戰

     編輯:Java 綜合教學

Java 多線程進階:Condition 條件變量詳解與生產者消費者實戰

Condition 將 Object 監視器方法(wait、notify、notifyAll)解耦為獨立對象,配合 Lock 實現更靈活的多等待隊列控制。Lock 替代 synchronized,Condition 替代 Object 監視器方法。

一、基礎範例:線程間信號通知

public class ConditionTest {
    public static void main(String[] args) {
        final Lock lock = new ReentrantLock();
        final Condition condition = lock.newCondition();

        Thread thread1 = new Thread(() -> {
            try {
                lock.lock();
                System.out.println("線程1:等待信號 " + Thread.currentThread());
                condition.await(); // 釋放鎖並阻塞
                System.out.println("線程1:收到信號 " + Thread.currentThread());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "thread1");
        thread1.start();

        Thread thread2 = new Thread(() -> {
            try {
                lock.lock();
                System.out.println("線程2:獲得鎖");
                Thread.sleep(500);
                System.out.println("線程2:發送信號");
                condition.signal(); // 喚醒一個等待線程
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "thread2");
        thread2.start();
    }
}

二、執行結果分析

線程1:等待信號 Thread[thread1,5,main]
線程2:獲得鎖
線程2:發送信號
線程1:收到信號 Thread[thread1,5,main]

執行流程示意圖

流程解析:

  1. thread1 獲取鎖,調用 await() 釋放鎖並進入等待隊列。
  2. thread2 獲取鎖,休眠 500ms 模擬處理,調用 signal() 喚醒 thread1。
  3. thread1 重新獲取鎖,從 await() 返回繼續執行。

三、核心方法對比

方法說明
await()當前線程釋放鎖並阻塞,直到被 signal()/signalAll() 喚醒或中斷
signal()喚醒一個等待在該 Condition 上的線程
signalAll()喚醒所有等待線程
awaitNanos(timeout)帶超時的等待,返回剩餘納秒數

四、實戰:有界隊列生產者消費者模型

public class BoundedQueue<T> {
    private final Object[] items;
    private int putIdx, takeIdx, count;
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();

    public BoundedQueue(int capacity) { items = new Object[capacity]; }

    public void put(T t) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length) notFull.await(); // 滿則等待
            items[putIdx] = t;
            if (++putIdx == items.length) putIdx = 0;
            ++count;
            notEmpty.signal(); // 通知消費者
        } finally { lock.unlock(); }
    }

    @SuppressWarnings("unchecked")
    public T take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0) notEmpty.await(); // 空則等待
            T t = (T) items[takeIdx];
            items[takeIdx] = null;
            if (++takeIdx == items.length) takeIdx = 0;
            --count;
            notFull.signal(); // 通知生產者
            return t;
        } finally { lock.unlock(); }
    }
}

使用兩個 Condition(notFull、notEmpty)分別控制生產與消費等待隊列,實現精確喚醒,避免 notifyAll() 的驚群效應。

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