JUC锁: ReentrantReadWriteLock详解

简介: `ReentrantReadWriteLock` 主要用于实现高性能的并发读取,而在写操作相对较少的场景中表现尤为突出。它保证了数据的一致性和线程安全,在合适的场合合理使用 `ReentrantReadWriteLock`,可以实现更加细粒度的控制,并显著提升应用性能。然而,需要注意它的复杂度较一般的互斥锁高,因此在选择使用时要仔细考虑其适用场景。

ReentrantReadWriteLock 是 Java 并发包(java.util.concurrent.locks)中提供的一种读写锁实现,它提供了一种高效的读写分离锁机制,允许多个线程同时读取共享资源,但只允许一个线程进行写操作,从而在保证数据一致性的前提下,提高了并发访问的效率。

ReentrantReadWriteLock 的特点

  1. 重入性:该锁支持重入。读线程可以重复获取读锁,写线程也可以重复获取写锁。同时,写线程获取写锁后也能获取读锁,但是读线程拥有读锁后不能升级为写锁。
  2. 公平性选择:构造函数接受一个布尔值,来决定锁是公平的还是非公平的。公平锁意味着等待时间最长的线程会优先得到锁。
  3. 锁降级:写线程持有写锁状态下可以获取读锁,进而释放写锁,这种机制叫做锁降级,可以缩小数据不一致的窗口期。
  4. 读写分离:多个线程可以同时持有读锁,而写锁是独占的。这种读写分离的设计能在很多场景下提高性能,尤其是读多写少的场景。

如何使用

ReentrantReadWriteLock 包含两个主要部分:ReadLockWriteLock。在操作数据前,需要根据数据的读写操作获取对应的锁。

ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
Lock readLock = readWriteLock.readLock();
Lock writeLock = readWriteLock.writeLock();

// 获取读锁进行读取操作
readLock.lock();
try {
    // 执行读取操作
} finally {
    readLock.unlock();
}

// 获取写锁进行写入操作
writeLock.lock();
try {
    // 执行写入操作
} finally {
    writeLock.unlock();
}

源码分析

ReentrantReadWriteLock 内部通过使用两个类:ReadLockWriteLock 来分别管理读锁状态和写锁状态。锁状态是通过维护一个整数(一个 32 位的 int)来实现的,其中高 16 位代表读状态,低 16 位代表写状态。

写锁 的获取和释放都要先检查读锁状态,保证没有线程在执行读操作时才能获取写锁。写锁是独占的,一旦写锁被获取,其他线程无法获取读锁或写锁。

读锁 的获取则允许在没有写锁或者当前线程持有写锁时成功。这意味着读锁是可以与其他读锁共享的,但一旦有线程请求写锁,新来的读锁必须等待,以避免写锁饿死。

关于线程的等待队列,ReentrantReadWriteLock 按公平和非公平方式分别维护了两个队列。公平锁会在队列中严格按照等待时间来分配锁,而非公平锁则可能会允许在队列外的线程抢到锁,这会降低上下文切换的开销从而提升效率,但同时也带来了潜在的公平性问题。

适用场景

ReentrantReadWriteLock 是为读多写少的并发场景而设计的。在读操作远远多于写操作的情况下,使用读写锁可以比使用独占锁(如 ReentrantLock)显著提高并发性能。

写操作期间不允许任何读操作的发生,若写操作很少但耗时,最好是快速完成以避免长时间阻塞读操作。

结论

ReentrantReadWriteLock 主要用于实现高性能的并发读取,而在写操作相对较少的场景中表现尤为突出。它保证了数据的一致性和线程安全,在合适的场合合理使用 ReentrantReadWriteLock,可以实现更加细粒度的控制,并显著提升应用性能。然而,需要注意它的复杂度较一般的互斥锁高,因此在选择使用时要仔细考虑其适用场景。

目录
相关文章
ReentrantReadWriteLock读写锁
ReentrantReadWriteLock读写锁
|
7月前
|
缓存 测试技术
ReentrantReadWriteLock 读写锁
ReentrantReadWriteLock 读写锁
46 0
|
7月前
|
安全 Java 测试技术
ReentrantReadWriteLock(可重入读写锁)源码解读与使用
ReentrantReadWriteLock(可重入读写锁)源码解读与使用
|
7月前
|
监控
多线程并发之读写锁(ReentranReadWriteLock&ReadWriteLock)使用详解
多线程并发之读写锁(ReentranReadWriteLock&ReadWriteLock)使用详解
120 0
|
Java
【Java并发】ReadWriteLock读写锁的使用
【Java并发】ReadWriteLock读写锁的使用
135 0
【Java并发】ReadWriteLock读写锁的使用
|
安全 Java 测试技术
读写锁还不会用StampedLock就Out了
读写锁还不会用StampedLock就Out了
144 0
读写锁还不会用StampedLock就Out了
|
缓存 Oracle 关系型数据库
可重入读写锁ReentrantReadWriteLock的使用详解
ReentrantReadWriteLock是一把可重入读写锁,这篇文章主要是从使用的角度帮你理解,希望对你有帮助。
226 0
可重入读写锁ReentrantReadWriteLock的使用详解
|
uml
除了读写锁,JUC 下面还有个 StampedLock!还不过来了解一下么?
在了解完 ReentrantLock 和 ReentrantReadWriteLock 之后,惊奇的发现 JUC 下还有一个 StampedLock 。 查阅资料发现是 JDK8 新增的一个锁。现在已经 JDK15 了,原谅我的孤陋寡闻,实在是业务开发中用的太少。那行吧,赶紧来看一下 StampedLock 到底是什么?为什么有了 ReentrantLock 和 ReentrantReadWriteLock 之后还要设计一个 StampedLock ?
127 0
|
Java
Java并发编程 - AQS 之 ReentrantReadWriteLock
Java并发编程 - AQS 之 ReentrantReadWriteLock
104 0
|
存储
可重入的读写锁-ReentrantReadWriteLock及AQS源码分析
可重入的读写锁-ReentrantReadWriteLock及AQS源码分析
124 0
可重入的读写锁-ReentrantReadWriteLock及AQS源码分析