ReentrantLock Condition 隨筆

Condition作用和Object.wait()和Object.notify()方法作用類似,但是wait()和notify()是和synchronized關鍵字結合使用的,而Condition是和ReentrantLock(重入鎖)相關聯的且更靈活:一個鎖實例,可以綁定多個Condition實例,實現多路通知;notify()方法進行通知時,是隨機進行選擇的,但重入鎖結合Condition對象,可以實現有選擇性的通知。

Condition接口API:

public interface Condition {
    //阻塞當前線程。使當前線程加入等待隊列中,同時釋放當前鎖,當其他線程使用signal()或者signalAll()方法時,線程會重新請求鎖,得到鎖後會繼續執行。或者當線程被中斷時,也能跳出等待。類似Object.wait()方法
    void await() throws InterruptedException;

    //調用該方法的前提是,當前線程已經成功獲得與該Condition對象綁定的重入鎖,否則調用該方法時會拋出IllegalMonitorStateException。
    //基本同await()方法,但是不會在等待過程中響應中斷。調用該方法後,結束等待的唯一方法是其它線程調用該條件對象的signal()或signalALL()方法。等待過程中如果當前線程被中斷,該方法仍然會繼續等待,同時保留該線程的中斷狀態。
    void awaitUninterruptibly();

    //調用該方法的前提是,當前線程已經成功獲得與該Condition對象綁定的重入鎖,否則調用該方法時會拋出IllegalMonitorStateException。
    //等待的的最大時間(單位爲納秒)。若指定時間內收到signal()或signalALL()則返回nanosTimeout減去已經等待的時間;若指定時間內未收到通知,則返回0或負數。
    //在等待過程中會響應中斷,若指定時間內有其它線程中斷該線程,則拋出InterruptedException並清除當前線程的打斷狀態。
    long awaitNanos(long nanosTimeout) throws InterruptedException;

    //與await()基本一致,不同點:指定時間之內沒有收到signal()或signalALL()或線程中斷會返回false;其它情況返回true。
    boolean await(long time, TimeUnit unit) throws InterruptedException;

   //與awaitNanos(long nanosTimeout)一致,不同點在於它不是等待指定時間,而是等待時間到達參數指定的某一時刻。
    boolean awaitUntil(Date deadline) throws InterruptedException;
    
    //喚醒一個等待隊列中的線程。與Object.notify()相似,但是signal()喚醒的線程與該Condition對象有關
    void signal();

   //喚醒等待隊列中所有線程。與object.notifyAll()相似,但是signalAll()喚醒的線程與該Condition對象有關
    void signalAll();
}

代碼Demo:
 

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

/**
 * 可重入鎖不同condition測試
 */
public class MyReentrantLockCondition implements Runnable {
    //共享鎖
    public static ReentrantLock lock = new ReentrantLock();
    //condition不共享
    public Condition condition;
    //共享變量
    //public static volatile int i = 1;

    public MyReentrantLockCondition() {
        //每個對象獨立condition
        this.condition = lock.newCondition();
    }

    public void await() {
        //自旋獲取鎖,直到獲取鎖成功
        lock.lock();
        try {
            System.out.println("-->await(): " + Thread.currentThread().getName() + " 獲取了鎖");
            //當前線程等待,釋放了鎖。類比Object.wait()。多線程操作共享變量是否有問題?沒有問題,喚醒時會重新獲取鎖重新獲取值
            condition.await();
            System.out.println("-->await(): " + Thread.currentThread().getName() + " 結束執行");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //任何情況都釋放鎖對象
            lock.unlock();
        }
    }

    public void signal() {
        lock.lock();
        try {
            //喚醒等待隊列中關聯condition的一個線程.類比Object.notify()
            condition.signal();
        } finally {
            lock.unlock();
        }
    }

    //測試
    public static void main(String[] args) throws InterruptedException {
        MyReentrantLockCondition condition1 = new MyReentrantLockCondition();
        MyReentrantLockCondition condition2 = new MyReentrantLockCondition();
        MyReentrantLockCondition condition3 = new MyReentrantLockCondition();
        MyReentrantLockCondition condition4 = new MyReentrantLockCondition();
        new Thread(condition1).start();
        new Thread(condition2).start();
        new Thread(condition3).start();
        new Thread(condition4).start();
        Thread.sleep(3000);
        //通知線程繼續執行
        condition1.signal();
        condition2.signal();
//        condition3.signal();

/*        MyReentrantLockCondition.lock.lock();
        try {
            condition4.condition.signalAll();
        } finally {
            MyReentrantLockCondition.lock.unlock();
        }*/
    }

    @Override
    public void run() {
        await();
    }
}

運行main()方法,可看到結果:

-->await(): Thread-0 獲取了鎖
-->await(): Thread-1 獲取了鎖
-->await(): Thread-2 獲取了鎖
-->await(): Thread-3 獲取了鎖
-->await(): Thread-0 結束執行
-->await(): Thread-1 結束執行

Thread-2、Thread-3沒有“結束執行”,還在一直等待signal()喚醒。

Condition在JDK源碼中的應用:

java.util.concurrent.ArrayBlockingQueue阻塞隊列:基於數組的阻塞隊列實現,在ArrayBlockingQueue內部,維護了一個定長數組,以便緩存隊列中的數據對象,還保存着兩個整形變量,分別標識着隊列的頭部和尾部在數組中的位置。

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {

    final Object[] items;

    int takeIndex;

    int putIndex;

    int count;

    final ReentrantLock lock;

    /** Condition for waiting takes */
    private final Condition notEmpty;

    /** Condition for waiting puts */
    private final Condition notFull;

    //往隊列中添加對象
    public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();//自旋獲取鎖
        try {
            while (count == items.length)//隊列已滿
                notFull.await();//進入等待隊列中等待,關聯notFull條件
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }

    //隊列中移除對象
    private E dequeue() {
        // assert lock.getHoldCount() == 1;
        // assert items[takeIndex] != null;
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        E x = (E) items[takeIndex];
        items[takeIndex] = null;
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        notFull.signal();//喚醒一個等待隊列中等待notFull條件的線程
        return x;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章