JAVA併發編程梳理與學習六(Lock和Condition 接口)

一、Lock
被稱爲顯示鎖。既然已經有synchronized爲什麼還要定義Lock呢?使用過synchronized關鍵字獲取鎖的都知道,synchronized獲取鎖和釋放鎖太死板,有以下缺點。
一旦一個線程用synchronized獲取鎖,別的競爭鎖的線程都要處於等待狀態,除非該線程執行完鎖定代碼或者線程拋出異常釋放鎖,別的等待線程纔有重新競爭鎖的機會。
所以會出現下面問題:一旦拿到鎖的線程,如果由於線程調用不釋放鎖的阻塞方法或者該線程要處理的業務耗時較長,那麼其他線程只能處於等待狀態,這樣會影響程序執行效率。所以爲了解決這些問題,更加靈活的獲取和釋放鎖,Lock應運而生。
Lock有一下優勢
1.可以超時獲取鎖:在指定時間之內獲取鎖,如果在這個時間之內沒有獲取鎖,則結束等待狀態;
2.能被中斷的獲取鎖:我們知道synchronized除非我們手動通過interrupted或者isInterrupted去判斷中斷狀態,線程才能響應中斷,在等待獲取鎖的過程中是不能響應中斷的。Lock則不同,正在等待獲取鎖的線程能響應中斷,當獲取鎖的線程被中斷時,中斷異常將會被拋出。
3.嘗試非阻塞的獲取鎖:當前線程嘗試獲取鎖,如果鎖處於空閒狀態,立馬獲取鎖,如果獲取不到也不會處於一直等待狀態
二、Lock標準用法及注意事項

lock.lock();
try{
  count++;//邏輯代碼
}finally{
lock.unlock()
}

注意:一定要在finally裏面釋放鎖,因爲要是在邏輯代碼下面釋放鎖,如果邏輯代碼報錯,鎖有可能得不到釋放,寫在finally裏面是爲了保證獲取鎖後能最終釋放
三、Lock常用api
在這裏插入圖片描述
四、ReentrantLock
我們知道Lock是java一個接口,要使用的話必須用它的實現類,ReentrantLock就是Lock一個常用實現類,ReentrantLock稱爲可重入鎖。什麼是可重入鎖,就是一個線程已經獲取到了該鎖,還可以重複申請該鎖的使用權。比如我們對一個遞歸方法加鎖,如果不支持可重入,那麼遞歸方法將無法進行下去,因爲第一拿到鎖後還沒釋放,其他所有線程都拿不到該鎖。synchronized隱式的支持可重入,ReentrantLock也是支持可重入
五、公平鎖和非公平鎖
公平鎖:顧名思義這個鎖是公平的,意思就是先申請獲取鎖的線程,當鎖被釋放後一定會先拿到鎖,也就是等待時間長的線程優先獲取鎖,鎖按時間順序獲取
非公平鎖:和公平鎖相反,等待時間最長的線程可能不會優先獲取鎖。比如,現在A、B、C3個線程在等待獲取鎖,我們知道,當鎖釋放的時間,cpu要重新進行上下文切調度等待獲取鎖的線程去獲取鎖,這個時間線程D突然來了,要申請鎖,那麼就能馬上獲取到鎖,而不管A、B、C線程,這就是非公平鎖。
比較:從上面分析可以看出,顯然非公平鎖的效率是高於公平鎖的。假設在進行上下文切換時間,線程D完成獲得、使用以及釋放這個鎖,這樣一來A並沒有延遲獲取鎖,B也完成了自己的任務。
ReentrantLock提供了一個構造函數,能夠控制鎖是否是公平的,默認是非公平的
六、讀寫鎖ReadWriteLock和ReentrantReadWriteLock
ReadWriteLock是接口,ReentrantReadWriteLock是ReadWriteLock的實現類,可以看ReadWriteLock接口源碼定義獲取讀鎖和寫鎖的方法
在這裏插入圖片描述
**這麼做的好處和體現的思想:**讀寫分離的思想。我們知道多線程之所以發生線程不敢全問題,主要是多個線程共同改變一個共享變量,一般讀是不會發生線程安全問題的,而無論是synchronized還是上面的ReentrantLock都是排他鎖,在同一時間只允許一個線程訪問,別的線程只能處於等待狀態。假如我們現在有一個讀多寫少的操作,如果使用排他鎖,無論是讀還是寫都只能同一時間一個進行,其實我們想過沒有讀操作是可以同時進行的,這樣是不是能極大提高讀的速度。ReentrantReadWriteLock就給我們提供了這種機制。
工作時2個鎖的互斥狀態:寫獨佔,讀共享,讀寫互斥。寫獨佔,一個線程拿到讀鎖,其他所有線程全部處於等待狀態;讀共享,一個線程拿到寫鎖,其餘讀的線程都可以繼續工作,但是寫鎖處於等待狀態(讀寫互斥);
七、condition接口
condition接口作用:我們仔細看Lock接口下面方法可以看到 Condition newCondition()方法,通過這個方法可以獲取Condition。Condition作用是什麼呢?我們知道,我們使用synchronized關鍵字實現鎖時間,會有Object的一組監視器方法wait()/wait(long timeout)/notify()/notifyAll()方法,這些方法和synchronized關鍵字使用可以實現等待/通知機制。而Condition也提供了類似Object類似於這些作用的方法,可以和Lock配合使用實現等待/通知機制
常用方法解讀
在這裏插入圖片描述
使用模板

Lock lock=new ReentrantLock();
Condition condition=lock.newCondition();
public void conditionWait() throws InterruptedException{
  lock.lock();
        try{
            condition.await();
        }finally {
            lock.unlock();
        }
}

public void conditionSignal() throws InterruptedException{
  lock.lock();
        try{
            condition.signal();
        }finally {
            lock.unlock();
        }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章