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,可以实现更加细粒度的控制,并显著提升应用性能。然而,需要注意它的复杂度较一般的互斥锁高,因此在选择使用时要仔细考虑其适用场景。

云服务器/高防CDN推荐

蓝易云国内/海外高防云服务器推荐


免备案五网CN2云服务器:www.tsyvps.com

蓝易云安全企业级高防CDN:www.tsycdn.com

持有增值电信营业许可证:B1-20222080【资质齐全】

蓝易云香港五网CN2 GIA/GT精品网络服务器。拒绝绕路,拒绝不稳定。

蓝易云是一家专注于香港及国内数据中心服务的提供商,提供高质量的服务器租用和云计算服务、包括免备案香港服务器、香港CN2、美国服务器、海外高防服务器、国内高防服务器、香港VPS等。致力于为用户提供稳定,快速的网络连接和优质的客户体验。
最后修改:2024 年 04 月 08 日
如果觉得我的文章对你有用,请随意赞赏