ReentrantLock和Condition理解及應(yīng)用

Condition:

Condition是一個(gè)多線程間協(xié)調(diào)通信的工具類,使得某個(gè),或者某些線程一起等待某個(gè)條件(Condition),只有當(dāng)該條件具備( signal 或者 signalAll方法被帶調(diào)用)時(shí) ,這些等待線程才會被喚醒,從而重新爭奪鎖。

ReentrantLock:

(重入鎖)是jdk的concurrent包提供的一種獨(dú)占鎖的實(shí)現(xiàn)。它繼承自Dong Lea的 AbstractQueuedSynchronizer(同步器),確切的說是ReentrantLock的一個(gè)內(nèi)部類繼承了AbstractQueuedSynchronizer,ReentrantLock只不過是代理了該類的一些方法,可能有人會問為什么要使用內(nèi)部類在包裝一層? 我想是安全的關(guān)系,因?yàn)锳bstractQueuedSynchronizer中有很多方法,還實(shí)現(xiàn)了共享鎖,Condition(稍候再細(xì)說)等功能,如果直接使ReentrantLock繼承它,則很容易出現(xiàn)AbstractQueuedSynchronizer中的API被無用的情況。

對比wati,notify,notifyAll

java 1.5 出現(xiàn)的顯式協(xié)作Condition接口的 await、signal、signalAll 也可以說是普通并發(fā)協(xié)作 wait、notify、notifyAll 的升級;普通并發(fā)協(xié)作 wait、notify、notifyAll 需要與synchronized配合使用,顯式協(xié)作Condition 的 await、signal、signalAll 需要與顯式鎖Lock配合使用(Lock.newCondition()),調(diào)用await、signal、signalAll方法都必須在lock 保護(hù)之內(nèi)。

和wait一樣,await在進(jìn)入等待隊(duì)列后會釋放鎖和cpu,當(dāng)被其他線程喚醒或者超時(shí)或中斷后都需要重新獲取鎖,獲取鎖后才會從await方法中退出,await同樣和wait一樣存在等待返回不代表?xiàng)l件成立的問題,所以也需要主動循環(huán)條件判斷;await提供了比wait更加強(qiáng)大的機(jī)制,譬如提供了可中斷或者不可中斷的await機(jī)制等;特別注意Condition也有wait、notify、notifyAll方法,因?yàn)槠湟彩荗bject,所以在使用顯式協(xié)作機(jī)制時(shí)千萬不要和synchronized 情況下的協(xié)作機(jī)制混合使用,避免出現(xiàn)詭異問題。

用一個(gè)stackoverflow的一個(gè)實(shí)現(xiàn)BlockingQueue例子讓大家印象深刻一點(diǎn):
用wait,notify,notifyAll實(shí)現(xiàn):

public class BlockingQueue<T> {
    private Queue<T> mQueue = new LinkedList<>();
    private int mCapacity;

    public BlockingQueue(int capacity) {
        this.mCapacity = capacity;
    }

    public synchronized void put(T element) throws InterruptedException{
        while (mQueue.size() == mCapacity){
            wait();
        }
        mQueue.add(element);
        notify();
    }

    public synchronized T take() throws InterruptedException{
        while (mQueue.isEmpty()){
            wait();
        }
        T item = mQueue.remove();
        notify();
        return item;
    }

}

用await,signal,signalAll實(shí)現(xiàn):

public class BlockingQueue<T> {
    private Queue<T> mQueue = new LinkedList<>();
    private int mCapacity;
    private Lock mLock = new ReentrantLock();
    private Condition mNotFull = mLock.newCondition();
    private Condition mNotEmpty = mLock.newCondition();

    public BlockingQueue(int capacity) {
        this.mCapacity = capacity;
    }

    public synchronized void put(T element) throws InterruptedException{
        mLock.lockInterruptibly();
        try {
            while (mQueue.size() == mCapacity){
                mNotFull.await();
            }
            mQueue.add(element);
            mNotEmpty.signal();
        }finally {
            mLock.unlock();
        }
    }

    public synchronized T take() throws InterruptedException{
        mLock.lockInterruptibly();
        try {
            while (mQueue.size() == 0){
                mNotEmpty.await();
            }
            T item = mQueue.remove();
            mNotFull.signal();
            return item;
        }finally {
            mLock.unlock();
        }
    }

}

怎么理解Condition

并發(fā)一枝花之 BlockingQueue

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容