读写锁 ReadWriteLock
读写锁维护了一对相关的锁,一个用于只读操作,一个用于写入操作。只要没有writer,读取锁可以由多个reader线程同时保持。写入锁是独占的。
互斥锁一次只允许一个线程访问共享数据,哪怕进行的是只读操作;读写锁允许对共享数据进行更高级别的并发访问:对于写操作,一次只有一个线程(write线程)可以修改共享数据,对于读操作,允许任意数量的线程同时进行读取。
与互斥锁相比,使用读写锁能否提升性能则取决于读写操作期间读取数据相对于修改数据的频率,以及数据的争用——即在同一时间试图对该数据执行读取或写入操作的线程数。
读写锁适用于读多写少的情况。
可重入读写锁 ReentrantReadWriteLock
属性
ReentrantReadWriteLock
也是基于 AbstractQueuedSynchronizer
实现的,它具有下面这些属性(来自Java doc文档):
- 获取顺序:此类不会将读取者优先或写入者优先强加给锁访问的排序。
- 非公平模式(默认):连续竞争的非公平锁可能无限期地推迟一个或多个reader或writer线程,但吞吐量通常要高于公平锁。
- 公平模式:线程利用一个近似到达顺序的策略来争夺进入。当释放当前保持的锁时,可以为等待时间最长的单个writer线程分配写入锁,如果有一组等待时间大于所有正在等待的writer线程的reader,将为该组分配读者锁。
- 试图获得公平写入锁的非重入的线程将会阻塞,除非读取锁和写入锁都自由(这意味着没有等待线程)。
- 重入:此锁允许reader和writer按照
ReentrantLock
的样式重新获取读取锁或写入锁。在写入线程保持的所有写入锁都已经释放后,才允许重入reader使用读取锁。
writer可以获取读取锁,但reader不能获取写入锁。 -
锁降级:重入还允许从写入锁降级为读取锁,实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。但是,从读取锁升级到写入锁是不可能的。
-
锁获取的中断:读取锁和写入锁都支持锁获取期间的中断。
-
Condition 支持:写入锁提供了一个
Condition
实现,对于写入锁来说,该实现的行为与ReentrantLock.newCondition()
提供的Condition
实现对ReentrantLock
所做的行为相同。当然,此Condition
只能用于写入锁。
读取锁不支持Condition
,readLock().newCondition()
会抛出UnsupportedOperationException
。 -
监测:此类支持一些确定是读取锁还是写入锁的方法。这些方法设计用于监视系统状态,而不是同步控制。