JUC锁-ReentrantReadWriteLock详解

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

ReentrantReadWriteLock 的特点

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

如何使用

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

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 内部通过使用两个类:ReadLock 和 WriteLock 来分别管理读锁状态和写锁状态。锁状态是通过维护一个整数(一个 32 位的 int)来实现的,其中高 16 位代表读状态,低 16 位代表写状态。

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

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

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

适用场景

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

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

posted @   qy98948221  阅读(0)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示