Oracle java官网关于可重入读写锁ReentrantReadWriteLock的解析
2.与ReadWriteLock的关系
public class ReentrantReadWriteLock extends Object implements ReadWriteLock, Serializable ReentrantReadWriteLock是接口ReadWriteLock的唯一实现类,支持与ReadWriteLock类似的语义。
3.这个类有以下特性:
1)Acquisition order(获取顺序)
(1) This class does not impose a reader or writer preference ordering for lock access. However, it does support an optional fairness policy. 这个类不强制锁访问的读取器或写入器首选顺序。然而,它确实支持可选的公平政策。 (2) Non-fair mode (default)默认非公平模式 When constructed as non-fair (the default), the order of entry to the read and write lock is unspecified, subject to reentrancy constraints. 当构造为非公平锁(默认值)时,读写锁的进入顺序是不指定的,受可重入性约束。 A nonfair lock that is continuously contended may indefinitely postpone one or more reader or writer threads, 持续争用的非公平锁可以无限期地推迟一个或多个读线程或写线程 but will normally have higher throughput than a fair lock. 但是通常会比公平锁有更高的吞吐量。 (3) Fair mode 公平模式 When constructed as fair, threads contend for entry using an approximately arrival-order policy. 当被构造为公平时,线程使用近似到达顺序策略来竞争进入。 When the currently held lock is released, either the longest-waiting single writer thread will be assigned the write lock, 当当前持有的锁被释放时,等待时间最长的单个写线程将被分配写锁, or if there is a group of reader threads waiting longer than all waiting writer threads, that group will be assigned the read lock. 或者,如果有一组读线程等待的时间比所有等待写线程的时间都长,那么该组将被分配读锁。 A thread that tries to acquire a fair read lock (non-reentrantly) will block if either the write lock is held, or there is a waiting writer thread. 试图获得公平读锁(不可重入)的线程,如果持有写锁,或者有一个等待的写线程,就会阻塞。 The thread will not acquire the read lock until after the oldest currently waiting writer thread has acquired and released the write lock. 在当前等待的最老的写线程获得并释放写锁之后,线程才会获得读锁。 Of course, if a waiting writer abandons its wait, leaving one or more reader threads as the longest waiters in the queue with the write lock free, then those readers will be assigned the read lock. 当然,如果一个正在等待的写线程放弃了它的等待,留下一个或多个读线程作为队列中最长的等待线程,而写锁是空闲的,然后这些读取器将被分配读锁。 A thread that tries to acquire a fair write lock (non-reentrantly) will block unless both the read lock and write lock are free (which implies there are no waiting threads). 试图获得公平写锁(不可重入)的线程将阻塞,除非读锁和写锁都是空闲的(这意味着没有等待线程)。 (Note that the non-blocking ReentrantReadWriteLock.ReadLock.tryLock() and ReentrantReadWriteLock.WriteLock.tryLock() methods do not honor this fair setting and will immediately acquire the lock if it is possible, regardless of waiting threads.) (请注意,非阻塞的reentrtreadwritelock.readlock.trylock()和reentrtreadwritelock . writelock . trylock()方法会忽视这个公平设置)
2)Reentrancy(可重入性)
(1) This lock allows both readers and writers to reacquire read or write locks in the style of a ReentrantLock. 这个锁允许读取器和写入器重新获得ReentrantLock风格的读或写锁。(即锁的可重入性) (2) Non-reentrant readers are not allowed until all write locks held by the writing thread have been released. 在写线程持有的所有写锁被释放之前,不允许不可重入的读取器. (3) Additionally, a writer can acquire the read lock, but not vice-versa. 此外,一个写入器可以获得读锁,但反之则不行。 (4) Among other applications, reentrancy can be useful when write locks are held during calls or callbacks to methods that perform reads under read locks. 在其他应用程序中,当在调用或回调在读锁下执行读操作的方法期间,持有写锁时,可重入性可能很有用 If a reader tries to acquire the write lock it will never succeed. 如果读取器试图获取写锁,它将永远不会成功
3)Lock downgrading(锁降级)
Reentrancy also allows downgrading from the write lock to a read lock, by acquiring the write lock,then the read lock and then releasing the write lock. 可重入性还允许将写锁降级为读锁,方法是先获取写锁,然后再获取读锁,然后释放写锁 However, upgrading from a read lock to the write lock is not possible. 但是,从读锁升级到写锁是不可能的。
4)Interruption of lock acquisition(锁获取中断)
The read lock and write lock both support interruption during lock acquisition. 读锁和写锁在获取锁时都支持中断。
5)Condition support(支持Condition)
The write lock provides a Condition implementation that behaves in the same way, with respect to the write lock, as the Condition implementation provided by ReentrantLock.newCondition() does for ReentrantLock. This Condition can, of course, only be used with the write lock. 写锁提供了一个条件实现,就写锁而言,它的行为方式与ReentrantLock. newcondition()提供的条件实现对ReentrantLock的行为方式相同。当然,这个条件只能用于写锁 The read lock does not support a Condition and readLock().newCondition() throws UnsupportedOperationException. 读锁不支持Condition和readLock().newCondition() throws UnsupportedOperationException方法
6)Instrumentation(仪表检测工具)
This class supports methods to determine whether locks are held or contended. 该类有确定锁是被持有还是被争用的方法。 These methods are designed for monitoring system state, not for synchronization control. 这些方法是为了监控系统状态而设计的,而不是为了同步控制。 比如: hasQueuedThread(Thread thread) Queries whether the given thread is waiting to acquire either the read or write lock. 查询给定线程是否正在等待获取读锁或写锁。 hasQueuedThreads() Queries whether any threads are waiting to acquire the read or write lock. 查询是否有线程正在等待获取读或写锁。 hasWaiters(Condition condition) Queries whether any threads are waiting on the given condition associated with the write lock. 查询是否有线程正在等待与写锁相关联的给定条件。 isWriteLocked() Queries if the write lock is held by any thread.查询写锁是否被任何线程持有 isWriteLockedByCurrentThread() Queries if the write lock is held by the current thread.查询写锁是否由当前线程持有
4.Sample usages(简单用法示例)
1)Downgrade by acquiring read lock before releasing write lock(通过在释放写锁之前获取读锁来降级)
Here is a code sketch showing how to perform lock downgrading after updating a cache 下面是一个代码草图,展示了如何在更新缓存后执行锁降级 (exception handling is particularly tricky when handling multiple locks in a non-nested fashion): (当以非嵌套方式处理多个锁时,异常处理特别棘手)
class CachedData {
Object data;
volatile boolean cacheValid;
final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
if (!cacheValid) {
data = ...
cacheValid = true;
}
rwl.readLock().lock();
} finally {
rwl.writeLock().unlock();
}
}
try {
use(data);
} finally {
rwl.readLock().unlock();
}
}
}
2)ReentrantReadWriteLock’s use in Collections(ReentrantReadWriteLock在集合中的使用)
ReentrantReadWriteLocks can be used to improve concurrency in some uses of some kinds of Collections. ReentrantReadWriteLocks可以用于在某些类型的集合的某些使用中提高并发性。 This is typically worthwhile only when the collections are expected to be large, accessed by more reader threads than writer threads, 这通常只适用于期望集合很大、由更多的读线程访问而不是写线程访问的情况 and entail operations with overhead that outweighs synchronization overhead. 并且需要操作的开销大于同步开销。 For example, here is a class using a TreeMap that is expected to be large and concurrently accessed. 例如,这里有一个使用TreeMap的类,它被认为是大的并且可以并发访问的。
class RWDictionary {
private final Map<String, Data> m = new TreeMap<String, Data>();
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
public Data get(String key) {
r.lock();
try { return m.get(key); }
finally { r.unlock(); }
}
public String[] allKeys() {
r.lock();
try { return m.keySet().toArray(); }
finally { r.unlock(); }
}
public Data put(String key, Data value) {
w.lock();
try { return m.put(key, value); }
finally { w.unlock(); }
}
public void clear() {
w.lock();
try { m.clear(); }
finally { w.unlock(); }
}
}
5.可重入读写锁ReentrantReadWriteLock总结
1) 支持公平/非公平模式;
(1)公平模式下,使用的并不是绝对而是近似到达顺序策略,具体详见3.3);
(2)非公平模式通常会比公平模式下有更大的吞吐量;
2) 适合用在读多写少,读耗时不会极短,且数据量较多(比如集合)的场景下
|