1. 程式人生 > >鎖:可重入鎖 可中斷鎖 公平鎖 讀寫鎖

鎖:可重入鎖 可中斷鎖 公平鎖 讀寫鎖

轉自:http://www.cnblogs.com/wihainan/p/4762800.html 侵刪

1.可重入鎖

如果鎖具備可重入性,則稱作為可重入鎖。

像synchronized和ReentrantLock都是可重入鎖,可重入性在我看來實際上表明瞭鎖的分配機制:

基於執行緒的分配,而不是基於方法呼叫的分配

舉個簡單的例子,當一個執行緒執行到某個synchronized方法時,比如說method1,而在method1中會呼叫另外一個synchronized方法method2,

此時執行緒不必重新去申請鎖,而是可以直接執行方法method2。

複製程式碼
class MyClass {
    
public synchronized void method1() { method2(); } public synchronized void method2() { } }
複製程式碼

上述程式碼中的兩個方法method1和method2都用synchronized修飾了,

假如某一時刻,執行緒A執行到了method1,此時執行緒A獲取了這個物件的鎖,而由於method2也是synchronized方法,假如synchronized不具備可重入性,此時執行緒A需要重新申請鎖。

但是這就會造成一個問題,因為執行緒A已經持有了該物件的鎖,而又在申請獲取該物件的鎖,這樣就會執行緒A一直等待永遠不會獲取到的鎖。

而由於synchronized和Lock都具備可重入性,所以不會發生上述現象。

 2.可中斷鎖

  可中斷鎖:顧名思義,就是可以相應中斷的鎖。

  在Java中,synchronized就不是可中斷鎖,而Lock是可中斷鎖。

  如果某一執行緒A正在執行鎖中的程式碼,另一執行緒B正在等待獲取該鎖,可能由於等待時間過長,執行緒B不想等待了,想先處理其他事情,我們可以讓它中斷自己或者在別的執行緒中中斷它,這種就是可中斷鎖。

  在前面演示lockInterruptibly()的用法時已經體現了Lock的可中斷性。

3.公平鎖

  公平鎖即儘量以請求鎖的順序來獲取鎖。比如同是有多個執行緒在等待一個鎖,當這個鎖被釋放時,等待時間最久的執行緒(最先請求的執行緒)會獲得該所,這種就是公平鎖。

  非公平鎖即無法保證鎖的獲取是按照請求鎖的順序進行的。這樣就可能導致某個或者一些執行緒永遠獲取不到鎖。

  在Java中,synchronized就是非公平鎖,它無法保證等待的執行緒獲取鎖的順序。

  而對於ReentrantLock和ReentrantReadWriteLock,它預設情況下是非公平鎖,但是可以設定為公平鎖。這一點由建構函式可知:

複製程式碼
1    
2     public ReentrantLock() {
3         sync = new NonfairSync();
4     }
5 
6 
7     public ReentrantLock(boolean fair) {
8         sync = (fair)? new FairSync() : new NonfairSync();
9     }
複製程式碼

在ReentrantLock中定義了2個靜態內部類,一個是NotFairSync,一個是FairSync,分別用來實現非公平鎖和公平鎖。

我們可以在建立ReentrantLock物件時,通過知道布林引數來決定使用 非公平鎖 還是公平鎖

如果引數為true表示為公平鎖,為fasle為非公平鎖。預設情況下,如果使用無參構造器,則是非公平鎖

另外在ReentrantLock類中定義了很多方法,比如:

  isFair()        //判斷鎖是否是公平鎖

  isLocked()    //判斷鎖是否被任何執行緒獲取了

  isHeldByCurrentThread()   //判斷鎖是否被當前執行緒獲取了

  hasQueuedThreads()   //判斷是否有執行緒在等待該鎖

在ReentrantReadWriteLock中也有類似的方法,同樣也可以設定為公平鎖和非公平鎖。

不過要記住,ReentrantReadWriteLock並未實現Lock介面,它實現的是ReadWriteLock介面。

4.讀寫鎖

  讀寫鎖將對一個資源(比如檔案)的訪問分成了2個鎖,一個讀鎖和一個寫鎖。

  正因為有了讀寫鎖,才使得多個執行緒之間的讀操作不會發生衝突。

  ReadWriteLock就是讀寫鎖,它是一個介面,ReentrantReadWriteLock實現了這個介面。

  可以通過readLock()獲取讀鎖,通過writeLock()獲取寫鎖。