深入探索Java并发库(JUC)中的ReentrantReadWriteLock

在这里插入图片描述

码到三十五 : 个人主页

心中有诗画,指尖舞代码,目光览世界,步履越千山,人间尽值得 !


在Java并发编程的世界中,锁是一种用于同步访问共享资源的机制。Java并发库(JUC)为我们提供了多种锁的实现,每种都有其特定的使用场景和优势。其中,ReentrantReadWriteLock是一种非常独特且实用的锁,它允许更高的并发性,特别适用于读多写少的场景。

目录

    • 一、ReentrantReadWriteLock的基本概念
    • 二、ReentrantReadWriteLock的特性
    • 三、ReentrantReadWriteLock原理解读
      • 3.1 核心组件
      • 3.2 实现机制
      • 3.3 源码骨架分析
    • 四、ReentrantReadWriteLock的使用
    • 五、ReentrantReadWriteLock的使用注意事项
    • 总结

一、ReentrantReadWriteLock的基本概念

ReentrantReadWriteLock,即可重入的读写锁,它维护了两把锁:读锁和写锁。读锁允许多个线程同时持有,从而允许多个线程同时读取共享资源,提高了并发读取的效率。而写锁则是独占的,同一时间只能被一个线程持有,用于保护写入共享资源的操作。

需要注意的是,读锁和写锁是互斥的。当写锁被持有时,其他线程无法获取读锁或写锁,从而保证了写入操作的独占性。而当读锁被持有时,虽然其他线程可以继续获取读锁,但无法获取写锁,这保证了在读取过程中共享资源不会被修改。

二、ReentrantReadWriteLock的特性

  1. 可重入性:ReentrantReadWriteLock允许同一个线程多次获取同一个锁,无论是读锁还是写锁。这使得线程可以在持有锁的情况下进行递归调用或多次访问共享资源,而不会产生死锁。

  2. 公平性选择:ReentrantReadWriteLock可以在创建时选择是否是公平的。公平锁意味着锁的获取顺序将按照线程请求锁的顺序来,即遵循先来先服务的原则;而非公平锁则不保证按照顺序分配锁,可能会导致某些线程长时间得不到锁。

  3. 锁降级:ReentrantReadWriteLock支持锁降级操作,即线程可以先获取写锁,然后释放写锁并获取读锁。这在某些场景下非常有用,比如线程在修改共享资源后需要读取修改后的结果。

三、ReentrantReadWriteLock原理解读

ReentrantReadWriteLock的实现机制相对复杂,涉及多个内部类和同步控制。下面我将简要概述其核心实现机制,并提供一些关键部分的源码分析。

3.1 核心组件

  1. Sync:ReentrantReadWriteLock内部的一个抽象队列同步器(AQS),它继承自AbstractQueuedSynchronizer,用于实现锁的核心逻辑。

  2. ReadLock:读锁的实现,内部持有一个Sync对象,用于实现读锁的获取和释放。

  3. WriteLock:写锁的实现,同样内部持有一个Sync对象,用于实现写锁的获取和释放。

3.2 实现机制

  • 状态表示:Sync内部使用一个整型的state字段来表示锁的状态。高16位表示读锁的持有次数,低16位表示写锁的持有次数。

  • 写锁获取:当线程尝试获取写锁时,会调用Sync的tryAcquire方法。如果state不为0(即已经有读锁或写锁被持有),则获取失败。如果成功获取写锁,会将state的低16位加1,并设置当前线程为锁的持有者。

  • 读锁获取:当线程尝试获取读锁时,会调用Sync的trySharedAcquire方法。如果state的低16位不为0(即有写锁被持有),则获取失败。如果成功获取读锁,会将state的高16位加1,并可能设置当前线程为锁的持有者(如果是第一个获取读锁的线程)。

  • 锁释放:无论是读锁还是写锁,释放时都会调用Sync的tryRelease或trySharedRelease方法。释放写锁时,会将state的低16位减1;释放读锁时,会将state的高16位减1。如果完全释放了锁(state变为0),则会唤醒等待队列中的其他线程。

  • 公平性:ReentrantReadWriteLock在构造时可以指定是否为公平锁。公平锁会按照线程请求锁的顺序来分配锁,而非公平锁则可能会跳过等待队列中的某些线程直接获取锁。

在这里插入图片描述

3.3 源码骨架分析

ReentrantReadWriteLock的源码较长且复杂,这里给出部分关键代码辅助分析。

// ReentrantReadWriteLock的部分内部类定义
public class ReentrantReadWriteLock
    implements ReadWriteLock, java.io.Serializable {

    // 内部抽象类Sync继承自AbstractQueuedSynchronizer
    abstract static class Sync extends AbstractQueuedSynchronizer {
        // ... 省略其他方法和字段 ...

        // 尝试获取写锁的方法(由WriteLock调用)
        final boolean tryAcquire(int acquires) {
            // ... 省略实现细节 ...
        }

        // 尝试释放写锁的方法(由WriteLock调用)
        final boolean tryRelease(int releases) {
            // ... 省略实现细节 ...
        }

        // 尝试获取读锁的方法(由ReadLock调用)
        final int tryAcquireShared(int acquires) {
            // ... 省略实现细节 ...
        }

        // 尝试释放读锁的方法(由ReadLock调用)
        final boolean tryReleaseShared(int releases) {
            // ... 省略实现细节 ...
        }

        // 判断是否处于读锁状态
        final boolean isHeldExclusively() {
            // ... 省略实现细节 ...
        }
    }

    // 非公平锁的实现类NonfairSync继承自Sync
    static final class NonfairSync extends Sync {
        // ... 省略其他方法和字段 ...
    }

    // 公平锁的实现类FairSync继承自Sync
    static final class FairSync extends Sync {
        // ... 省略其他方法和字段 ...
    }

    // 读锁的实现类ReadLock实现Lock接口
    public static class ReadLock implements Lock, java.io.Serializable {
        // ... 省略其他方法和字段 ...

        // 读锁的lock方法实现
        public void lock() {
            sync.acquireShared(1);
        }

        // 读锁的unlock方法实现
        public void unlock() {
            sync.releaseShared(1);
        }
    }

    // 写锁的实现类WriteLock实现Lock接口
    public static class WriteLock implements Lock, java.io.Serializable {
        // ... 省略其他方法和字段 ...

        // 写锁的lock方法实现
        public void lock() {
            sync.acquire(1);
        }

        // 写锁的unlock方法实现
        public void unlock() {
            sync.release(1);
        }
    }

    // ... 省略其他方法和字段 ...
}

ReentrantReadWriteLock定义了两个内部类ReadLock和WriteLock来实现读锁和写锁的功能。它们内部都持有一个Sync对象,用于实际的锁操作。Sync是一个继承自AbstractQueuedSynchronizer的抽象类,它实现了锁的核心逻辑。具体的公平性和非公平性锁的实现则通过FairSync和NonfairSync两个类来完成,它们分别继承自Sync。

四、ReentrantReadWriteLock的使用

下面是一个使用ReentrantReadWriteLock的代码,其中包含一个共享资源(一个简单的计数器),多个读线程和写线程将并发地访问这个资源。读线程只会读取计数器的值,而写线程会修改计数器的值。

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {

    // 共享资源:一个简单的计数器
    private int counter = 0;

    // 创建一个ReentrantReadWriteLock对象
    private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    // 获取读锁
    private final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();

    // 获取写锁
    private final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();

    // 读操作:增加读计数
    public int readCounter() {
        readLock.lock(); // 加读锁
        try {
            // 模拟读操作的耗时
            Thread.sleep(10);
            return counter;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return -1;
        } finally {
            readLock.unlock(); // 释放读锁
        }
    }

    // 写操作:增加计数器的值
    public void incrementCounter() {
        writeLock.lock(); // 加写锁
        try {
            // 模拟写操作的耗时
            Thread.sleep(10);
            counter++;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            writeLock.unlock(); // 释放写锁
        }
    }

    // 读线程类
    class ReaderThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println("读线程" + Thread.currentThread().getId() + "读取计数器值:" + readCounter());
            }
        }
    }

    // 写线程类
    class WriterThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                incrementCounter();
                System.out.println("写线程" + Thread.currentThread().getId() + "增加计数器值");
            }
        }
    }

    // 测试方法
    public static void main(String[] args) {
        ReadWriteLockExample example = new ReadWriteLockExample();

        // 启动多个读线程和写线程
        for (int i = 0; i < 3; i++) {
            new Thread(example.new ReaderThread()).start();
            new Thread(example.new WriterThread()).start();
        }
    }
}

我们定义了一个ReadWriteLockExample类,它包含一个计数器counter,一个ReentrantReadWriteLock对象以及对应的读锁和写锁。我们定义了两个方法readCounterincrementCounter来分别执行读操作和写操作,并在执行前后分别加锁和释放锁。

我们还定义了两个内部类ReaderThreadWriterThread来分别代表读线程和写线程。在main方法中,我们创建了多个读线程和写线程并启动它们,以模拟并发访问共享资源的场景。

五、ReentrantReadWriteLock的使用注意事项

  1. 避免锁升级:与锁降级相反,锁升级(从读锁升级到写锁)是不被支持的。如果线程已经持有了读锁并试图获取写锁,将会导致死锁。因此,在设计并发程序时应尽量避免这种情况的发生。

  2. 注意读写锁的互斥性:虽然多个线程可以同时持有读锁,但写锁是独占的。在设计并发程序时,应充分考虑读写锁的互斥性,避免因为不恰当的锁使用导致并发性能下降或死锁等问题。

  3. 选择合适的公平性策略:根据实际需求选择合适的公平性策略是非常重要的。公平锁可以确保所有线程都有机会获取锁,避免了某些线程长时间得不到锁的情况;但非公平锁在某些场景下可能具有更高的并发性能。

总结

ReentrantReadWriteLock是Java并发库中一种非常实用的读写锁实现,它允许多个线程同时读取共享资源,提高了程序的并发性能。在使用时需要注意正确获取和释放锁,避免死锁等问题;同时根据实际需求选择合适的公平性策略也是非常重要的。通过深入了解和合理使用ReentrantReadWriteLock,我们可以编写出更高效、更安全的并发程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/477724.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

简易指南:国内ip切换手机软件怎么弄

在网络访问受到地域限制的情况下&#xff0c;使用国内IP切换手机软件可以帮助用户轻松访问被屏蔽的内容&#xff0c;扩展网络体验。以下是虎观代理小二分享的使用国内IP切换手机软件的简易指南。并提供一些注意事项。 如何在手机上使用国内IP切换软件 步骤一&#xff1a;选择I…

PHP连接达梦数据库

PDO是一种在PHP中连接数据库的接口&#xff0c;可以通过PDO接口使用PHP连接达梦数据库。 1、安装PHP环境 检查当前环境是否安装PHP [rootlocalhost ~]# php -v 当前环境并未安装PHP&#xff0c;需要进行安装&#xff0c;选择安装PHP7.3版本。 2、安装 epel-release源和源管…

工程信号的去噪和(分类、回归和时序)预测

&#x1f680;【信号去噪及预测论文代码指导】&#x1f680; 还为小论文没有思路烦恼么&#xff1f;本人专注于最前沿的信号处理与预测技术——基于信号模态分解的去噪算法和深度学习的信号&#xff08;回归、时序和分类&#xff09;预测算法&#xff0c;致力于为您提供最精确、…

【Python爬虫】网络爬虫:信息获取与合规应用

这里写目录标题 前言网络爬虫的工作原理网络爬虫的应用领域网络爬虫的技术挑战网络爬虫的伦理问题结语福利 前言 网络爬虫&#xff0c;又称网络爬虫、网络蜘蛛、网络机器人等&#xff0c;是一种按照一定的规则自动地获取万维网信息的程序或者脚本。它可以根据一定的策略自动地浏…

常用的6个的ChatGPT网站,国内可用!

GPTGod &#x1f310; 链接&#xff1a; GPTGod &#x1f3f7;️ 标签&#xff1a; GPT-4 免费体验 支持API 支持绘图 付费选项 &#x1f4dd; 简介&#xff1a;GPTGod 是一个功能全面的平台&#xff0c;提供GPT-4的强大功能&#xff0c;包括API接入和绘图支持。用户可以选择免…

【阿里魔搭】modelscope包下载安装

最终解决方案&#xff1a;使用源码安装modelscope 这里写目录标题 问题描述&#xff1a;pip安装包冲突安装步骤 问题描述&#xff1a;pip安装包冲突 一开始的是在3.11的虚拟环境下使用命令行pip install "modelscope[nlp]" -f https://modelscope.oss-cn-beijing.al…

DUSt3R:简化三维重建

3D 重建是从二维 (2D) 图像创建对象或场景的 3D 虚拟表示的任务&#xff0c;可用于模拟、可视化或本地化等多种目的。 它广泛应用于计算机视觉、机器人和虚拟现实&#xff08;VR&#xff09;等多个领域。 在基本设置中&#xff0c;3D 重建方法输入一对图像 I1 和 I2&#xff0c…

字体测试集:选取、应用与兼容性指南

1. 字体测试集 本人非专业字体工作者&#xff0c;字体测试集为个人经验总结整理&#xff0c;仅供参考 那时&#xff0c;天下人的口音、言语都是一样。 南去經三國&#xff0c;東來過五湖 南去经三国&#xff0c;东来过五湖 永东国酬爱郁灵鹰袋 0Oo1lI ga The quick brown fox j…

6个免费的ChatGPT网站

AI 大模型的出现给时代带来了深远的影响&#xff1a; 改变了产业格局&#xff1a;AI 大模型的发展推动了人工智能技术在各行业的广泛应用&#xff0c;改变了传统产业的运作方式&#xff0c;促进了新兴产业的崛起&#xff0c;如智能驾驶、医疗健康、金融科技等。提升了科学研究…

微软发布首款AI PC ,产业链有望迎来新一轮量价齐升

3月21日晚&#xff0c;微软举办主题为“办公新时代”的线上新品发布会&#xff0c;发布Surface Pro 10和Surface Laptop 6&#xff0c;新品将搭载基于英特尔酷睿Ultra或高通骁龙X Elite的处理器&#xff0c;配备新一代NPU&#xff0c;以增强AI性能。 这两款AI PC将支持“AI Exp…

土地利用的时序建模

1、LULC 模型的现状 最近的土地利用和土地覆盖 (LULC) 建模进展来自两种方法。 在一种方法中&#xff0c;现有模型适用于 LULC&#xff0c;而在另一种方法中&#xff0c;模型架构是针对 LULC 明确设计的。 随着大型基础模型的兴起&#xff0c;人工智能和深度学习取得了重大进…

数据结构 二叉树 力扣例题AC——代码以及思路记录

LCR 175. 计算二叉树的深 某公司架构以二叉树形式记录&#xff0c;请返回该公司的层级数。 AC int calculateDepth(struct TreeNode* root) {if (root NULL){return 0;}else{return 1 fmax(calculateDepth(root->left), calculateDepth(root->right));} } 代码思路 …

【Linux C | 多线程编程】线程的创建、线程ID、线程属性

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a;2024-03-22 0…

SSC9211_USB-CAM解决方案

一、方案描述 SSC9211是一种用于USB-CAM应用程序跟场景的高度集成的SOC产品。平台本身基于ARM层-A7双核&#xff0c;内置16位&#xff0c;64M的DDR2&#xff0c;集成了图像传感器接口、高级ISP、高性能JPEG编码器和其他丰富的外设接口。支持单&#xff0c;双 MIPI sensor方案&…

H3C--堆叠(IRF)

拓扑图 配置流程 配置SW1与SW2堆叠 一、SW1&#xff1a; shutdown 物理端口配置堆叠优先级&#xff0c;优先级高的成为主设备创建堆叠逻辑接口&#xff0c;将物理接口加入到堆叠逻辑接口中 二、SW1&#xff1a; sysname SW1 # irf member 1 priority 6 # irf-port 1/1port…

基于时空上下文(STC)的运动目标跟踪算法,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

windowsVMware虚拟机中扩展linux磁盘空间

1.虚拟磁盘扩容 VM中&#xff0c;关闭linux虚拟机&#xff0c;直接编辑虚拟机-硬盘-扩展磁盘容量 2.通过Gparted工具进行LINUX系统磁盘分区 未分区挂载前可以看到/挂载点下空间为20G&#xff1a; 通过虚拟机-快照-拍摄快照&#xff0c;操作前可拍摄快照&#xff08;便于恢复之前…

科技云报道:造完“大模型”,“具身智能”将引领AI下一个浪潮?

科技云报道原创。 资深机器人专家Eric Jang不久前曾预言&#xff1a;“ChatGPT 曾在一夜之间出现。我认为&#xff0c;有智慧的机器人技术也将如此。” 3月13日深夜&#xff0c;一段人形机器人的视频开始热传。 在视频中&#xff0c;Figure的人形机器人&#xff0c;可以完全…

基于java+springboot+vue实现的健身房管理系统(文末源码+Lw+ppt)23-523

摘 要 健身房管理的以往工作流程繁杂、多样、管理复杂与设备维护繁琐。而如今计算机已完全能够胜任健身房管理工作&#xff0c;而且更加准确、方便、快捷、高效、清晰、透明&#xff0c;它完全可以克服以上所述的不足之处。这将给查询信息和管理带来很大的方便&#xff0c;从…

从0写一个问卷调查APP的第13天-1

1.今日任务 我也只是一个大学生&#xff0c;有什么思路不对的地方给我指出来哟! 分析&#xff1a;上次我们实现了任务调查的插入。但是我们插入的问卷调查只有它的标题&#xff0c;也就是这个问卷调查是什么我们告诉数据库了&#xff0c;但是现在我们还没有给它添加任何问题&…