引言

ReadWriteLock包含一对关联的锁,一个用于只读,另一个用于写。readLock只要没有写者,可以同时被多个读线程所有, writeLock是独占的。
writeLock操作的内存同步效果对关联的readLock也有效
读写锁允许在访问共享数据时具有比互斥锁所允许的更高级别的并发性,因为虽然写锁每次只有一个线程,但是只有写线程可以修改共享的数据,在许多情况下,任意数量的读线程都可以并发地读取数据。
但是有个前提:这种并发性的增加只有在多处理器上才能完全实现,而且只有在共享数据的访问模式合适时才能实现。

读写锁ReadWriteLock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface ReadWriteLock {
/**
* Returns the lock used for reading.
*
* @return the lock used for reading
*/
Lock readLock();

/**
* Returns the lock used for writing.
*
* @return the lock used for writing
*/
Lock writeLock();
}

ReentrantReadWriteLock实现了ReadWriteLock接口,该类不强制对锁访问设置读写器优先级排序。但是,它支持可选的公平策略。

Non-fair mode

当构造为非公平(默认)时,读写锁的entry顺序是未指定的,受可重入性约束。持续争用的非公平锁可能无限期地延迟一个或多个读线程或写线程,但通常具有比公平锁更高的吞吐量。

Fair mode

当构造为公平时,线程使用先后顺序策略争锁。当当前持有的锁被释放时,要么为等待时间最长的单个写线程分配写锁,要么为等待时间比所有等待写线程都长的一组读线程分配读锁。

可重入

readers 和 writers 以ReentrantLock的样式重新获取读锁或写锁。在写线程持有的所有写锁都被释放之前,不允许使用非重入读取器。此外,writer可以获得读锁,但反之则不行。

Lock downgrading

可重入性还允许从写锁降级为读锁,方法是获取写锁,然后是读锁,然后释放写锁。然而,从读锁升级到写锁是不可能的。

Interruption of lock acquisition

读锁和写锁都支持在获取锁时中断。

内部类

Sync

ReentrantReadWriteLock的同步实现,继承自AbstractQueuedSynchronizer,内部重写了tryRelease,tryAcquire,tryReleaseShared,tryAcquireShared,属于核心。

FairSync和NonfairSync

公平模式与非公平模式同步器,重写了Sync类中的writerShouldBlock和readerShouldBlock方法,用于处理当前线程在获取读锁和写锁阻塞时的策略。

ReadLock

读锁的实现,重写了接口Lock中共享锁的一些方法,内部维护的同步器与写锁是同一个同步器。不支持Condition条件队列。

WriteLock

写锁也是实现了Lock接口,但是实现了独占锁的一些方法,内部维护的同步器和读锁的是同一个,支持Condition条件队列。

ReentrantReadWriteLock的构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Creates a new {@code ReentrantReadWriteLock} with
* default (nonfair) ordering properties.
*/
public ReentrantReadWriteLock() {
//默认非公平方式,增加吞吐量
this(false);
}

/**
* Creates a new {@code ReentrantReadWriteLock} with
* the given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantReadWriteLock(boolean fair) {
//根据策略创建公平同步器或者非公平同步器
sync = fair ? new FairSync() : new NonfairSync();
//创建读锁和写锁,由此可见,他们内部的同步器是同一个。
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}

读锁和写锁内部方法实现

可以从源码中得知,他们内部获取锁,释放锁,都是通过AQS实现,所以分析读写锁,相当于分析Sync中重写的AQS的方法。
以后再分析。