当前位置: 首页 > article >正文

读写锁: ReentrantReadWriteLock

在多线程编程场景中,对共享资源的访问控制极为关键。传统的锁机制在同一时刻只允许一个线程访问共享资源,这在读写操作频繁的场景下,会因为读操作相互不影响数据一致性,而造成不必要的性能损耗。ReentrantReadWriteLock(可重入读写锁)的出现有效解决了这一问题,它允许在同一时间内多个线程进行读操作,同时保证写操作的原子性与线程安全性。本文将深入探讨ReentrantReadWriteLock的原理、使用方式及其应用场景。

ReentrantReadWriteLock 原理剖析

ReentrantReadWriteLock是 Java 并发包java.util.concurrent.locks中的成员,它将对共享资源的访问分为读锁和写锁。读锁允许多个线程同时获取,因为读操作不会修改共享资源,所以多个线程同时读不会产生数据不一致问题。而写锁是独占的,同一时间仅能有一个线程获取写锁,以此保证写操作的原子性和线程安全。

可重入特性

ReentrantReadWriteLock具备可重入特性,即同一个线程能够多次获取读锁或写锁。当线程获取锁后,锁的持有计数会增加,每释放一次锁,持有计数就减少,当持有计数为 0 时,锁才真正被释放。该特性避免了线程在递归调用时出现死锁情况。

公平性与非公平性

ReentrantReadWriteLock支持公平和非公平两种模式。在公平模式下,线程获取锁的顺序依照请求的先后顺序进行;在非公平模式下,线程获取锁的顺序不确定,新请求的线程有可能比等待队列中的线程更早获取到锁。非公平模式在高并发场景下通常性能更佳,因为它减少了线程切换的开销。

代码示例

以下通过一个简单示例代码展示ReentrantReadWriteLock的基本用法。假设存在一个共享缓存,多个线程可能读取缓存中的数据,也可能更新缓存。

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {
    private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private static final ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
    private static final ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
    private static String cacheData;

    public static void main(String[] args) {
        // 模拟读线程
        Thread readThread1 = new Thread(() -> {
            readLock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " 开始读取数据");
                if (cacheData == null) {
                    System.out.println("缓存中没有数据");
                } else {
                    System.out.println("读取到的数据: " + cacheData);
                }
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + " 读取数据结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                readLock.unlock();
            }
        });

        // 模拟写线程
        Thread writeThread1 = new Thread(() -> {
            writeLock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " 开始写入数据");
                cacheData = "新的数据";
                System.out.println(Thread.currentThread().getName() + " 写入数据结束");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                writeLock.unlock();
            }
        });

        readThread1.start();
        writeThread1.start();

        try {
            readThread1.join();
            writeThread1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在上述代码中:

  1. 首先创建了ReentrantReadWriteLock对象,以及它的读锁和写锁。
  2. readThread1线程模拟读操作,获取读锁后,尝试读取缓存数据。由于读锁允许多个线程同时获取,所以多个读线程可以同时执行读操作。
  3. writeThread1线程模拟写操作,获取写锁后,更新缓存数据。在写锁被持有期间,其他线程无论是读还是写操作,都将被阻塞,直到写锁被释放。

使用场景

  1. 缓存系统:在缓存系统中,读操作的频率通常远高于写操作。使用ReentrantReadWriteLock可以允许多个线程同时读取缓存,只有在更新缓存时才需要获取写锁,从而大大提高系统的并发性能。
  2. 数据库连接池:数据库连接池需要管理多个数据库连接,多个线程可能会同时获取和释放连接信息。通过ReentrantReadWriteLock,读操作(如获取连接状态)可以并发执行,而写操作(如添加或移除连接)则保证线程安全。
  3. 文件系统:在文件系统中,多个线程可能会同时读取文件内容,而写操作(如文件修改)则需要保证原子性。ReentrantReadWriteLock可以有效管理对文件的读写访问,确保数据的一致性。

结语

感谢您的阅读!如果您对 ReentrantReadWriteLock 或其他并发编程话题有任何疑问或见解,欢迎继续探讨。


http://www.kler.cn/a/532359.html

相关文章:

  • 2025_2_4 C语言中关于free函数及悬空指针,链表的一级指针和二级指指针
  • Java | CompletableFuture详解
  • 深度学习 Pytorch 基础网络手动搭建与快速实现
  • [250203] glibc 2.41 发布 | Flutter 颜色管理库 color_palette_plus 2.0.0 发布
  • [HOT 100] 2824. 统计和小于目标的下标对数目
  • Vuex状态管理
  • 【C++STL标准模板库】二、STL三大组件
  • 数据结构与算法——二分查找
  • e2studio开发RA4M2(6)----GPIO外部中断(IRQ)配置
  • 机器学习中的关键概念:通过SKlearn的MNIST实验深入理解
  • Linux+Docer 容器化部署之 Shell 语法入门篇 【Shell 替代】
  • 神经网络常见激活函数-sigmoid函数
  • deepseek接入pycharm 进行AI编程
  • 高精度乘法(高×高)
  • 438.找到字符串中所有字母异位词
  • 数据库课程设计基于Java+MySQL+JDBC+JavaSwing的停车场管理系统源代码+数据库,进出车辆登记,车位管理
  • OSCP - Other Machines - CuteNews
  • oracle: 数据操纵语言DML/批量更新
  • C++11详解(一) -- 列表初始化,右值引用和移动语义
  • leetcode 1124. 表现良好的最长时间段
  • 开发板目录 /usr/lib/fonts/ 中的字体文件 msyh.ttc 的介绍【微软雅黑(Microsoft YaHei)】
  • Linux基础 ——tmux vim 以及基本的shell语法
  • MySQL知识点总结(十八)
  • starrocks最佳实践、行业实践
  • 014-STM32单片机实现矩阵薄膜键盘设计
  • day38|leetcode 322零钱兑换,279.完全平方数,139.单词拆分