ReadWriteLock與ReentrantReadWriteLock

weixin_33896726發表於2016-01-06

      JAVA的JUC包中的鎖包括"獨佔鎖"和"共享鎖"。JUC中的共享鎖有:CountDownLatch、CyclicBarrier、Semaphore、ReentrantReadWriteLock等。本章會以ReentrantReadWriteLock為藍本對共享鎖進行說明。

一、ReentrantLock與ReentrantReadWriteLock

    說到ReentrantReadWriteLock,首先要做的是與ReentrantLock劃清界限。它和後者都是單獨的實現,彼此之間沒有繼承或實現的關係。

ReentrantLock 實現了標準的互斥操作,也就是一次只能有一個執行緒持有鎖,也即所謂獨佔鎖的概念。顯然這個特點在一定程度上面減低了吞吐量,實際上獨佔鎖是一種保守的鎖策略,在這種情況下任何“讀/讀”,“寫/讀”,“寫/寫”操作都不能同時發生。但是同樣需要強調的一個概念是,鎖是有一定的開銷的,當併發比較大的時候,鎖的開銷就比較客觀了。所以如果可能的話就儘量少用鎖,非要用鎖的話就嘗試看能否改造為讀寫鎖。

ReadWriteLock 描述的是:一個資源能夠被多個讀執行緒訪問,或者被一個寫執行緒訪問,但是不能同時存在讀寫執行緒。也就是說讀寫鎖使用的場合是一個共享資源被大量讀取操作,而只有少量的寫操作(修改資料)。

參考:http://my.oschina.net/adan1/blog/158107?fromerr=M4d1zh4s

二、ReadWriteLock 和 ReentrantReadWriteLock

     ReadWriteLock,顧名思義,是讀寫鎖。它維護了一對相關的鎖 — — "讀取鎖"和"寫入鎖",一個用於讀取操作,另一個用於寫入操作。     

    "讀取鎖"用於只讀操作,它是"共享鎖",能同時被多個執行緒獲取。     

    "寫入鎖"用於寫入操作,它是"獨佔鎖",寫入鎖只能被一個執行緒鎖獲取。 注意:不能同時存在讀取鎖和寫入鎖!

     ReadWriteLock是一個介面。ReentrantReadWriteLock是它的實現類,ReentrantReadWriteLock包括子類ReadLock和WriteLock。

 

ReentrantReadWriteLock的UML類圖如下:

       讀寫鎖的機制:"讀-讀"不互斥、"讀-寫"互斥、"寫-寫"互斥。即在任何時候:只有一個執行緒在寫入;執行緒正在讀取的時候,寫入操作等待;執行緒正在寫入的時候,其他執行緒的寫入操作和讀取操作都要等待;

讀鎖的加鎖原始碼片段如下:

寫鎖的加鎖原始碼片段下:

相比較而言,就是上面說過的一旦寫鎖加鎖時發現有其他執行緒進行了操作,則將當前執行緒放置於執行緒等待佇列中——之後再喚醒。而讀操作鎖直接進行了共享執行緒,併發讀取。 

鎖降級:從寫鎖變成讀鎖;鎖升級:從讀鎖變成寫鎖。讀鎖是可以被多執行緒共享的,寫鎖是單執行緒獨佔的。也就是說寫鎖的併發限制比讀鎖高,這可能就是升級/降級名稱的來源。

如下程式碼會產生死鎖,因為同一個執行緒中,在沒有釋放讀鎖的情況下,就去申請寫鎖,這屬於鎖升級,ReentrantReadWriteLock是不支援的。

            ReadWriteLock rtLock = new ReentrantReadWriteLock();  

            rtLock.readLock().lock();  

            System.out.println("get readLock.");  

            rtLock.writeLock().lock();  

            System.out.println("blocking");  

            ReadWriteLock rtLock = new ReentrantReadWriteLock();

            rtLock.readLock().lock();
            System.out.println("get readLock.");
            rtLock.writeLock().lock();
            System.out.println("blocking");

ReentrantReadWriteLock支援鎖降級,如下程式碼不會產生死鎖。

            ReadWriteLock rtLock = new ReentrantReadWriteLock();  

            rtLock.writeLock().lock();  

            System.out.println("writeLock");  

            rtLock.readLock().lock();  

            System.out.println("get read lock");   

相關文章