ReentrantReadWriteLock
類, 顧名思義, 是一種讀寫鎖, 它是 ReadWriteLock
接口的直接實現, 該類在內部實現了具體獨佔鎖特點的寫鎖, 以及具有共享鎖特點的讀鎖, 和 ReentrantLock
一樣, ReentrantReadWriteLock
類也是通過定義內部類實現AQS框架的API來實現獨佔/共享的功能.
ReentrantLock
屬於排他鎖, 這些鎖在同一時刻只允許一個線程進行訪問, 但是在大多數場景下, 大部分時間都是提供讀服務, 而寫服務佔有的時間較少. 而且, 讀服務不存在數據競爭問題, 如果一個線程在讀時禁止其他線程讀勢必會導致性能降低. 所以就提供了讀寫鎖.
讀寫鎖維護着一對鎖, 一個讀鎖和一個寫鎖. 通過分離讀鎖和寫鎖, 使得併發性比一般的排他鎖有了較大的提升:
- 在同一時間, 可以允許多個讀線程同時訪問.
- 但是, 在寫線程訪問時, 所有讀線程和寫線程都會被阻塞.
讀寫鎖的主要特性:
- 公平性:支持公平性和非公平性.
- 重入性:支持重入. 讀寫鎖最多支持 65535 個遞歸寫入鎖和 65535 個遞歸讀取鎖.
- 鎖降級:遵循獲取寫鎖, 再獲取讀鎖, 最後釋放寫鎖的次序, 如此寫鎖能夠降級成爲讀鎖.
ReadWriteLock
讀寫鎖 ReentrantReadWriteLock
實現接口 ReadWriteLock
, 該接口維護了一對相關的鎖, 一個用於只讀操作, 另一個用於寫入操作. 只要沒有 writer
, 讀取鎖可以由多個 reader
線程同時保持. 寫入鎖是獨佔的.
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
ReadWriteLock
定義了兩個方法. readLock()
返回用於讀操作的鎖, writeLock()
返回用於寫操作的鎖.
ReentrantReadWriteLock
java.util.concurrent.locks.ReentrantReadWriteLock
定義如下.
/** 內部類 讀鎖 */
private final ReentrantReadWriteLock.ReadLock readerLock;
/** 內部類 寫鎖 */
private final ReentrantReadWriteLock.WriteLock writerLock;
final Sync sync;
/** 使用默認(非公平)的排序屬性創建一個新的 ReentrantReadWriteLock */
public ReentrantReadWriteLock() {
this(false);
}
/** 使用給定的公平策略創建一個新的 ReentrantReadWriteLock */
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
/** 返回用於寫入操作的鎖 */
@Override
public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
/** 返回用於讀取操作的鎖 */
@Override
public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; }
abstract static class Sync extends AbstractQueuedSynchronizer {
/**
* 省略其餘源代碼
*/
}
public static class WriteLock implements Lock, java.io.Serializable {
/**
* 省略其餘源代碼
*/
}
public static class ReadLock implements Lock, java.io.Serializable {
/**
* 省略其餘源代碼
*/
}
ReentrantReadWriteLock
與 ReentrantLock
一樣, 其鎖主體依然是 Sync, 它的讀鎖、寫鎖都是依靠 Sync 來實現的.
所以 ReentrantReadWriteLock
實際上只有一個鎖, 只是在獲取讀取鎖和寫入鎖的方式上不一樣而已, 它的讀寫鎖其實就是兩個類: ReadLock
、writeLock
, 這兩個類都是lock實現.
在 ReentrantLock
中, 使用 Sync ( 實際是 AQS ) 的 int
類型的 state
來表示同步狀態, 表示鎖被一個線程重複獲取的次數.
但是, 讀寫鎖 ReentrantReadWriteLock
內部維護着一對讀寫鎖, 如果要用一個變量維護多種狀態, 需要採用 “按位切割使用” 的方式來維護這個變量, 將其切分爲兩部分: 高16爲表示讀, 低16爲表示寫.