共计 1978 个字符,预计需要花费 5 分钟才能阅读完成。
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 为表示写.