深入ReentrantReadWriteLock

简介: 深入ReentrantReadWriteLock

ReentrantReadWriteLock出现的原因

  • 首先synchronized和ReentrantLock都是互斥锁,一个线程在获取锁资源之后另一个线程只能等待
  • 假设有一种情况是读多写少,并且确保线程安全。可以使用ReentrantReadWriteLock实现
  • ReentrantReadWriteLock的特点是读读不互斥,可以并发执行;读写操作则是互斥的。

代码效果显示

/**
 * @author 舒一笑
 * @date 2023/6/1
 */
public class Test17 {

    static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    static ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
    static ReentrantReadWriteLock.ReadLock readLock =lock.readLock();

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            // 这里现在是读锁
            readLock.lock();
            try {
                System.out.println("子线程是读锁");
                Thread.sleep(50000000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally {
                readLock.unlock();
            }
        }).start();

        Thread.sleep(1000);
        // 这里现在也是读锁
        readLock.lock();
        try {
            System.out.println("主线程");
        } finally {
            readLock.unlock();
        }

    }
}
  • 读读锁效果演示

  • 写读锁效果演示

ReentrantReadWriteLock(重新输入读写锁定)锁的实现原理分析

  • 还是基于AQS实现,同样都是对state的操作。获取锁资源成功便执行判断之后的方法体逻辑,否则便会阻塞到AQS队列中去排队


  • 查看对AQS方法在ReentrantReadWriteLock中的实现可以知道
  • 读锁操作是基于state的高16位的操作
  • 写锁操作是基于state的低16位的操作,所以在锁重入的时候同样是对state的操作,但是范围却比小了


  • ReentrantReadWriteLock依旧是可重入锁
    tryAcquire(int acquires)方法的分析
  • 当前线程不持有锁资源,c的值是0;尝试获取锁资源、CAS拿锁。


写锁释放锁流程和源码分析

  • tryRelease(arg)方法分析

读锁分析

  • 读锁加锁源码分析
  • 方法体里面没拿到锁资源就去排队

  • tryAcquireShared(arg)方法分析

  • 读锁重入流程分析
  • 读锁的重入主要就是基于下面这部分的源码的实现。
  • 通过对r是否为0的判断来证明当前是不是第一个拿到读锁资源的线程
  • 判断满足那么将firstRead置为当前线程。并将firstReadCount置为1
  • 要是第一个判断不满足。那么便会判断当前线程是不是第一个获取读锁资源的线程。要是是的话那么就会firstReadHoldcount++
  • 要是还是不满足那么就说明当前线程不是第一个获取读锁资源的线程。那就在方法体中获取最后一个拿到锁资源的线程。并判断当前线程是否是最后一个拿到读锁资源的线程。要是不是那就将当前线程设置为cachedHoldCounter。
  • 如果在最内部的判断中当前线程是之前的cachedHoldCounter,那就判断当前的重入次数是不是0,重新设置当前线程锁重入信息到readHolds,就是包装了ThreadLocal中,完成初始化操作。重入次数是0;将count次数++

  • 读锁加锁后续fullTryAcquireShared(current)方法分析

  • 读锁在获取锁资源之后doAcquireShared(arg)方法分析

    setHeadAndPropagate(node, r);方法分析

读锁释放锁流程

  • doReleaseShared()方法分析
相关文章
|
存储 关系型数据库 MySQL
【分布式和微服务1】一篇文章详细了解分布式和微服务的基本概念
【分布式和微服务1】一篇文章详细了解分布式和微服务的基本概念
2230 0
|
数据采集 自然语言处理 搜索推荐
图文详解 DFS 和 BFS | 算法必看系列知识二十四
深度优先遍历(Depth First Search, 简称 DFS) 与广度优先遍历(Breath First Search)是图论中两种非常重要的算法,生产上广泛用于拓扑排序,寻路(走迷宫),搜索引擎,爬虫等,也频繁出现在高频面试题中。
38618 6
图文详解 DFS 和 BFS | 算法必看系列知识二十四
|
9月前
|
缓存 安全 Java
探索并发编程中ConcurrentHashMap的使用
综上所述,ConcurrentHashMap是Java并发编程中不可或缺的一部分,它通过与操作系统、JVM及硬件特性紧密结合,为开发高效且线程安全的并发应用程序提供了强大的数据结构支持。掌握ConcurrentHashMap的使用是实现高性能并发程序的关键步骤之一。
346 117
|
6月前
|
安全 Ubuntu Linux
Metasploit Pro 5.0.0-2026031101 (Linux, Windows) - 专业渗透测试框架
Metasploit Pro 5.0.0-2026031101 (Linux, Windows) - 专业渗透测试框架
330 3
Metasploit Pro 5.0.0-2026031101 (Linux, Windows) - 专业渗透测试框架
|
6月前
|
自然语言处理 Linux API
OpenClaw阿里云/本地喂饭级部署步骤+多模态落地手册:音视频转写、图文生成及免费模型配置教程
2026年,OpenClaw(Clawdbot)已从单一文本交互工具进化为支持多模态处理的综合AI执行平台,其核心突破在于实现了音视频、图文、文本的跨模态协同处理——无需复杂插件整合,即可通过自然语言指令完成语音转写、视频字幕生成、图片分析、图文创作等复杂任务。这种多模态能力彻底打破了传统工具的场景局限,使其在内容创作、办公自动化、知识管理等领域的实用性大幅提升。
1486 0
|
存储 自然语言处理 算法
【LeetCode 热题100】208:实现 Trie (前缀树)(详细解析)(Go语言版)
本文详细解析了力扣热题 208——实现 Trie(前缀树)。Trie 是一种高效的树形数据结构,用于存储和检索字符串集合。文章通过插入、查找和前缀匹配三个核心操作,结合 Go 语言实现代码,清晰展示了 Trie 的工作原理。时间复杂度为 O(m),空间复杂度也为 O(m),其中 m 为字符串长度。此外,还探讨了 Trie 的变种及应用场景,如自动补全和词典查找等。适合初学者深入了解 Trie 结构及其实际用途。
680 14
|
安全 Java 开发者
Lock锁和AQS之间的关系与区别:基于第一原理的深入分析
【11月更文挑战第26天】在Java并发编程中,锁(Lock)和队列同步器(AbstractQueuedSynchronizer,简称AQS)是两个核心概念。它们为多线程环境下的同步和互斥提供了强大的支持。本文将从第一原理出发,深入探讨Lock锁和AQS之间的关系与区别,同时分析它们的相关概念、业务场景、历史背景、功能点以及底层原理,并使用Java代码进行模拟实现。
433 1
|
安全 Java 程序员
Java集合之战:ArrayList vs LinkedList,谁才是你的最佳选择?
本文介绍了 Java 中常用的两个集合类 ArrayList 和 LinkedList,分析了它们的底层实现、特点及适用场景。ArrayList 基于数组,适合频繁查询;LinkedList 基于链表,适合频繁增删。文章还讨论了如何实现线程安全,推荐使用 CopyOnWriteArrayList 来提升性能。希望帮助读者选择合适的数据结构,写出更高效的代码。
1209 3
|
消息中间件 存储 监控
|
人工智能 算法 决策智能
动态规划之背包问题(01背包问题、完全背包问题、方案数填满型背包问题)
动态规划之背包问题(01背包问题、完全背包问题、方案数填满型背包问题)
963 1

热门文章

最新文章