本文对读写锁源码进行了比较详细的分析。
另外可以参考可重入锁 ReentrantLock 的分析:Java并发Concurrent包的锁(三)——ReentrantLock源码分析
ReadWriteLock接口
ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是独占的。
public interface ReadWriteLock {
// 获得读锁
Lock readLock();
// 获得写锁
Lock writeLock();
}
与互斥锁相比,读-写锁允许对共享数据进行更高级别的并发访问。写线程虽然一次只有一个访问数据,但读线程可以同时读取,而在实际中,读取往往都是大量的,写入是偶尔的,读-写锁利用了这一点。从理论上讲,与互斥锁相比,使用读-写锁所允许的并发性增强将带来更大的性能提高。在实践中,只有在多处理器上并且只在访问模式适用于共享数据时,才能完全实现并发性增强。
如果数据不常修改,而主要用于搜索,适合使用读写锁;而如果数据更新十分频繁,数据大部分时间都被每个线程所独占,这种情况并发也提高不了太多效率。而且如果读取的操作用时太多,那么读写锁本身的开销就是最大的执行成本。所以具体问题还是要具体分析。
ReentrantReadWriteLock的Sync
读写锁引用了 Sync 类,和 ReentrantLock 的 Sync 一样是通过 AbstractQueuedSynchronizer 进行扩展的,下面对其代码进行分析:
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 6317671515068378041L;
/*
* 锁状态state是int型,读写分为两部分,各用一个无符号short来表示
* 低位的表示写锁即独享锁,高位的表示读锁共享数
*/
// 这个16是两个字节,一个short的长度
static final int SHARED_SHIFT = 16;
// 1左移16位,为00000000 00000001 00000000 00000000
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
// 1左移16位,减1,为65535,读写的获取锁的最大次数
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
// 右移16位,获取c高位的16位,表示读锁的共享总数(高位2字节全0)
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
// 和两个字节的全1字节与操作,高位2字节全0,获取写锁的总数
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
// 每个线程的计数器,保存读锁共享数
static final class HoldCounter {
int count = 0;
final long tid = getThreadId(Thread.currentThread());
}
// ThreadLocal的子类
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
// 初始化方法,返回HoldCounter
public HoldCounter initialValue() {
return new HoldCounter();
}
}
// 读线程的一个集合,但不包括最后一个读线程和第一个读线程
private transient ThreadLocalHoldCounter readHolds;
// 最后一个读线程的计数
private transient HoldCounter cachedHoldCounter;
// 第一个读线程
private transient Thread firstReader = null;
// 第一个读线程的计数
private transient int firstReaderHoldCount;
Sync() {
readHolds = new ThreadLocalHoldCounter();
setState(getState()); // ensures visibility of readHolds
}
// 读锁的阻塞
abstract boolean readerShouldBlock();
// 写锁的阻塞
abstract boolean writerShouldBlock();
// 释放写锁
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
/