源码分析— java读写锁ReentrantReadWriteLock
言#
今天看Jraft的时候发现了很多地方都用到了读写锁,所以心血来潮想要分析以下读写锁是怎么实现的。
先上一个doc里面的例子:
class CachedData { Object data; volatile boolean cacheValid; final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); void processCachedData() { //加上一个读锁 rwl.readLock().lock(); if (!cacheValid) { // Must release read lock before acquiring write lock //必须在加写锁之前释放读锁 rwl.readLock().unlock(); rwl.writeLock().lock(); try { // Recheck state because another thread might have // acquired write lock and changed state before we did. //双重检查 if (!cacheValid) { //设置值 data = ... cacheValid = true; } // Downgrade by acquiring read lock before releasing write lock //锁降级,反之则不行 rwl.readLock().lock(); } finally { //释放写锁,但是仍然持有写锁 rwl.writeLock().unlock(); // Unlock write, still hold read } } try { use(data); } finally { //释放读锁 rwl.readLock().unlock(); } } }}
我们一般实例化一个ReentrantReadWriteLock,一般是调用空的构造器创建,所以默认使用的是非公平锁
public ReentrantReadWriteLock() { this(false); } public ReentrantReadWriteLock(boolean fair) { //默认使用的是NonfairSync sync = fair ? new FairSync() : new NonfairSync(); readerLock = new ReadLock(this); writerLock = new WriteLock(this); } //分别调用writeLock和readLock会返回读写锁实例 public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; } public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; }
ReentrantReadWriteLock内部类Sync
abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 6317671515068378041L; //位移量 //在读写锁中,state是一个32位的int,所以用state的高16位表示读锁,用低16位表示写锁 static final int SHARED_SHIFT = 16; //因为读锁是高16位,所以用1向左移动16位表示读锁每次锁状态变化的量 static final int SHARED_UNIT = (1 << SHARED_SHIFT); //最大的可重入次数 static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;