ReentrantReadWriteLock
类, 顾名思义, 是一种读写锁, 它是 ReadWriteLock
接口的直接实现, 该类在内部实现了具体 独占锁特点的写锁
, 以及具有 共享锁特点的读锁
, 和 ReentrantLock
一样, ReentrantReadWriteLock
类也是通过定义内部类实现AQS框架的API来实现独占/共享的功能.
ReentrantLock
属于排他锁, 这些锁在同一时刻只允许一个线程进行访问, 但是在大多数场景下, 大部分时间都是提供读服务, 而写服务占有的时间较少. 而且, 读服务不存在数据竞争问题, 如果一个线程在读时禁止其他线程读势必会导致性能降低. 所以就提供了读写锁.
读写锁维护着一对锁, 一个读锁和一个写锁. 通过分离读锁和写锁, 使得并发性比一般的排他锁有了较大的提升:
读写锁的主要特性:
读写锁 ReentrantReadWriteLock
实现接口 ReadWriteLock
, 该接口维护了一对相关的锁, 一个用于只读操作, 另一个用于写入操作. 只要没有 writer
, 读取锁可以由多个 reader
线程同时保持. 写入锁是独占的.
public interface ReadWriteLock { Lock readLock(); Lock writeLock(); }
ReadWriteLock
定义了两个方法. readLock()
返回用于读操作的锁, writeLock()
返回用于写操作的锁.
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为表示写.