1. 程式人生 > >顯式鎖(四)Lock的等待通知機制Condition

顯式鎖(四)Lock的等待通知機制Condition

lock == 等待隊列 urn 一個 AI 移除 等待時間 font

?? 任意一個Java對象,都擁有一組監視器方法(定義在根類Object上),主要包括:wait( )、wait(long timeout)、notify()、notifyAll()方法;這些方法與關鍵字synchronized結合使用,可以實現 隱式鎖的等待/通知機制。而顯示鎖Lock也實現了等待/通知機制;Condition接口也提供了類似Object的監視器方法,與Lock配合使用可以實現 顯式鎖的等待/通知機制,但是兩者在使用方式和功能特性有所差別。總得來說,Condition接口更加靈活,功能更多:

  • Condition 接口是支持多個等待隊列,也稱為條件隊列,即根據不同的條件進入不同的等待隊列,相應的,用戶便可以只在指定的等待隊列上喚醒線程,而不是喚醒所有的線程。而 Object監視器 則只能有一個等待隊列。
  • Condition 接口還提供了對中斷不敏感的等待方法,即當處於等待狀態時,是不會被中斷的。而Object監視器 不支持不可中斷的等待。
  • Condition 接口除了提供了超時等待方法之外,還提供了等待直到將來某個時間段的方法;Object監視器只有超時等待的方法。

Condition 接口的方法:

方法名稱 描 述
void await() throws InterruptedException 造成當前線程在接到通知或被中斷之前一直處於等待狀態。即發生以下兩種情況,將會從await()方法返回:
1、其他某個線程調用此 Condition 的 signal()、signalAll()方法;
2、其他某個線程中斷當前線程
void awaitUninterruptibly() 造成當前線程在接到通知之前一直處於等待狀態。 與await()方法相比,這是不可中斷的等待方法
long awaitNanos(long nanosTimeout) throws InterruptedException 造成當前線程在接到通知、被中斷或到達指定等待時間之前一直處於等待狀態。
返回值:此方法返回時,距離超時的剩余時間,即返回值就是(nanosTimeout - 實際耗時);如果返回值是0或者負數,那麽認定已經超時
boolean await(long time, TimeUnit unit) throws InterruptedException 造成當前線程在接到通知、被中斷或到達指定等待時間之前一直處於等待狀態。
返回值:如果在從此方法返回前檢測到等待時間超時(到達指定時間),則返回 false,否則返回 true
此方法在行為上等效於: awaitNanos(unit.toNanos(time)) > 0
boolean awaitUntil(Date deadline) throws InterruptedException 造成當前線程在接到通知、被中斷或到達指定最後期限之前一直處於等待狀態。
返回值:如果在從此方法返回前檢測到等待時間超時(到達指定時間),則返回 false,否則返回 true
void signal() 喚醒一個等待線程。如果所有的線程都在等待此條件,則選擇其中的一個喚醒。在從 await 返回之前,該線程必須重新獲取鎖。
void signalAll() 喚醒所有等待線程。 如果所有的線程都在等待此條件,則喚醒所有線程。在從 await 返回之前,每個線程都必須重新獲取鎖。

@ Example Condition 的例子

public class BoundedQueue<T> {
    private Object[] item;
    //添加的下標、刪除的下標、數組的當前數量
    private int addIndex,removeIndex,count;
    private Lock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();
    
    public BoundedQueue(int size){
        item = new Object[size];
    }
    
    //添加一個元素,如果數組滿,則添加線程進入等待狀態,直到有空位
    public void add(T t) throws InterruptedException{
        lock.lock();
        try{
            while(count == item.length){
                //可中斷的等待,如果沒有剩余空間,那麽就進入notFull的等待隊列
                notFull.wait();
            }
            item[addIndex] = t;
            if(++addIndex == item.length){//模擬環數組,一直插入,直到尾部,又重新從頭部插入
                addIndex = 0;
            }
            count++;
            //剛插入一個元素,不為空的條件滿足,可喚醒等待在notEmpty隊列上的線程
            notEmpty.signal();
        }finally {
            lock.unlock();
        }
    }
    
    //從頭部移除一個元素,如果數組為空,則等待,直到數組不為空
    public T remove(){
        lock.lock();
        try{
            while(count == 0){
                //不可中斷的等待,不為空的條件不滿足,就會一直等待
                notEmpty.awaitUninterruptibly();;
            }
            Object x = item[removeIndex];
            if(++removeIndex == item.length){
                removeIndex = 0;
            }
            count--;
            //剛移除一個元素,數組沒有滿的條件符合,喚醒等待在notFull上的線程
            notFull.signal();
            return (T)x;
        }finally{
            lock.unlock();
        }
    }
}

顯式鎖(四)Lock的等待通知機制Condition