ReentrantReadWriteLock
ReentrantReadWriteLock
重入锁ReentrantLock是排他锁,排他锁在同一时刻仅有一个线程可以进行访问,但是在大多数场景下,大部分时间都是提供读服务,而写服务占有的时间较少。然而读服务不存在数据竞争问题,如果一个线程在读时禁止其他线程读势必会导致性能降低。所以就提供了读写锁。
读写锁维护着一对锁,一个读锁和一个写锁。通过分离读锁和写锁,使得并发性比一般的排他锁有了较大的提升:在同一时间可以允许多个读线程同时访问,但是在写线程访问时,所有读线程和写线程都会被阻塞。
读写锁的主要特性:
- 公平性:支持公平性和非公平性。
- 重入性:支持重入。读写锁最多支持65535个递归写入锁和65535个递归读取锁。
- 锁降级:遵循获取写锁、获取读锁在释放写锁的次序,写锁能够降级成为读锁
读写锁ReentrantReadWriteLock实现接口ReadWriteLock,该接口维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是独占的。
源码读取
//读写锁的默认构造方法是一个非公平锁
public ReentrantReadWriteLock() {
this(false);
}
//会同时创建一个读锁和一个写锁
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
//通过这两个方法可以获取读锁和写锁
public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; }
//读写锁内部也是通过Sync继承队列同步器来实现同步
abstract static class Sync extends AbstractQueuedSynchronizer
读写锁中的方法和可重入锁大部分是一致的,只是在添加了读锁更多的实现:
public void lock() {
sync.acquireShared(1);
}
锁降级
如果当前线程在获取读锁的时候发现已经有别的线程获取了写锁,则返回false,在队列中阻塞等待。如果当前线程在获取读锁的时候发现自己已经获取了写锁,则进行锁降级,降为读锁。
参考资料: