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为表示写.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。