Java并发编程-读写锁(ReentrantReadWriteLock)

简介: 章节目录ReentrantReadWriteLock 特性读写锁接口示例读写锁的实现分析读写状态设计写锁的释放与获取读锁的释放与获取锁降级1. ReentrantReadWriteLock 特性1.1 读写锁定义读写锁维护了一对锁,一个读锁,一个写锁,通过分离读锁写锁,使得并发性相比一般的排他锁有了很大提升。

章节目录

  • ReentrantReadWriteLock 特性
  • 读写锁接口示例
  • 读写锁的实现分析
    • 读写状态设计
    • 写锁的释放与获取
    • 读锁的释放与获取
    • 锁降级

1. ReentrantReadWriteLock 特性

1.1 读写锁定义

读写锁维护了一对锁,一个读锁,一个写锁,通过分离读锁写锁,使得并发性相比一般的排他锁有了很大提升。
AI 代码解读

1.2 读写锁使用场景

1.读写锁比较适用于读多写少的应用场景。
2.读写锁在统一时刻可以允许多个读线程访问,但是在写线程访问时,所有的读线程、其他写线程均被阻塞。
AI 代码解读

1.3 读写锁的优点

1.保证写操作对读操作的可见性
2.在读多写少的情况下的并发性的提升
3.读写锁简化可读写交互场景的编程方式
AI 代码解读

2.读写锁接口示例

如下为使用读写锁操作缓存的示例

package org.seckill.lock;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteCache {
    //充当cache
    static Map<String, Object> map = new HashMap<String, Object>();
    //实例化读写锁对象
    static ReentrantReadWriteLock reentrantReadWriteLock =
            new ReentrantReadWriteLock();
    //实例化读锁
    static Lock r = reentrantReadWriteLock.readLock();
    //实例化写锁
    static Lock w = reentrantReadWriteLock.writeLock();

    //获取缓存中值
    public static final Object get(String key) {
        r.lock();
        try {
            return map.get(key);
        } finally {
            r.unlock();
        }
    }

    //写缓存中值,并返回对应value
    public static final Object set(String key, Object obj) {
        w.lock();
        try {
            return map.put(key, obj);
        } finally {
            w.unlock();
        }
    }

    //清空所有内容
    public static final void clear() {
        w.lock();
        try {
            map.clear();
        } finally {
            w.unlock();
        }
    }
}

AI 代码解读

如上所示:

1.Cache组合一个非线程安全的HashMap做为缓存实现,同时使用读写锁的
读锁和写锁来保证Cache是线程安全的。
2.在读操作get(String key)方法中,需要使用读锁,这使得并发访问该方法时不
会被阻塞。
3.写锁put(String key,Object object)方法和clear()方法,在更新HashMap时必须
提前获取写锁,当获取写锁后,其他线程对于读锁和写锁的获取都被阻塞,只
有写锁释放之后,其他的读写操作才能继续操作,也就是说写锁其实是排他
锁、互斥锁。
4.最终,读锁提升了读操作的并发性,也保证了每次写操作对所有后续读操作
的可见性,同时简化了编程方式,对应1.3
 
AI 代码解读

3.读写锁的实现分析

3.1 读写状态设计

1.读写锁同样依赖自定义同步器实现同步功能
2.ReentrantLock 中同步状态表示锁被一个线程重复获取的次数。
3.读写锁自定义同步器需要在同步状态上维护多个读线程和一个写线程的状态。
4.读写锁同步器采用在一个4字节的整形变量上使用 按位切割 的方式来维护读
写线程的同步状态。高16位用来表示读,低16位用来表示写。
5.写状态增加1,表示当前线程获取写锁,则 Status = S(当前同步状态)+1,当读
状态加1时,Status = S+(1<<16)
AI 代码解读

3.2 写锁的获取与释放
如下源码所示:

 protected final boolean tryAcquire(int acquires) {
            /*
             * Walkthrough:
             * 1. If read count nonzero or write count nonzero
             *    and owner is a different thread, fail.
             * 2. If count would saturate, fail. (This can only
             *    happen if count is already nonzero.)
             * 3. Otherwise, this thread is eligible for lock if
             *    it is either a reentrant acquire or
             *    queue policy allows it. If so, update state
             *    and set owner.
             */
            Thread current = Thread.currentThread();
            int c = getState();
            //获取独占锁(写锁)的被获取的数量
            int w = exclusiveCount(c);
            if (c != 0) {
                // (Note: if c != 0 and w == 0 then shared count != 0)
                //1.如果同步状态不为0,且写状态为0,则表示当前同步状态被读锁获取
                //2.或者当前拥有写锁的线程不是当前线程
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // Reentrant acquire
                setState(c + acquires);
                return true;
            }
            if (writerShouldBlock() ||
                !compareAndSetState(c, c + acquires))
                return false;
            setExclusiveOwnerThread(current);
            return true;
        }
AI 代码解读

3.3 读锁的释放与获取

protected final int tryAcquireShared(int unused) {
    for(;;) {
        int c = getState();
        int nextc = c + (1<<16);
        if(nextc < c) {
           throw new Error("Maxumum lock count exceeded");
        }
        if(exclusiveCount(c)!=0 && owner != Thread.currentThread())
           return -1;
        if(compareAndSetState(c,nextc))
           return 1;
    }
}
AI 代码解读

如果其他线程获取了写锁,则当前线程获取读锁失败,进入等待状态。
如果当前线程获取了写锁或者写锁未被获取,则当前线程安全,依靠CAS保证增加读状态,成功获取锁。

3.4 锁降级

锁降级是指当前把持住写锁,再获取到读锁,随后释放(先前拥有的)写锁的过程。

锁降级过程中的读锁的获取是否有必要,答案是必要的。主要是为了保证数据的可见性,如果当前线程不获取读锁而直接释放写锁,假设此刻另一个线程获取的写锁,并修改了数据,那么当前线程就步伐感知到线程T的数据更新,如果当前线程遵循锁降级的步骤,那么线程T将会被阻塞,直到当前线程使数据并释放读锁之后,线程T才能获取写锁进行数据更新。

目录
打赏
0
0
0
0
6
分享
相关文章
2025 更新必看:Java 编程基础入门级超级完整版指南
本教程为2025更新版Java编程基础入门指南,涵盖开发环境搭建(SDKMAN!管理JDK、VS Code配置)、Java 17+新特性(文本块、Switch表达式增强、Record类)、面向对象编程(接口默认方法、抽象类与模板方法)、集合框架深度应用(Stream API高级操作、并发集合)、模式匹配与密封类等。还包括学生成绩管理系统实战项目,涉及Maven构建、Lombok简化代码、JDBC数据库操作及JavaFX界面开发。同时提供JUnit测试、日志框架使用技巧及进阶学习资源推荐,助你掌握Java核心技术并迈向高级开发。
145 5
java 编程基础入门级超级完整版教程详解
这份文档是针对Java编程入门学习者的超级完整版教程,涵盖了从环境搭建到实际项目应用的全方位内容。首先介绍了Java的基本概念与开发环境配置方法,随后深入讲解了基础语法、控制流程、面向对象编程的核心思想,并配以具体代码示例。接着探讨了常用类库与API的应用,如字符串操作、集合框架及文件处理等。最后通过一个学生成绩管理系统的实例,帮助读者将理论知识应用于实践。此外,还提供了进阶学习建议,引导学员逐步掌握更复杂的Java技术。适合初学者系统性学习Java编程。资源地址:[点击访问](https://pan.quark.cn/s/14fcf913bae6)。
144 2
2025 年 Java 秋招面试必看 Java 并发编程面试题实操篇
Java并发编程是Java技术栈中非常重要的一部分,也是面试中的高频考点。本文从基础概念、关键机制、工具类、高级技术等多个方面进行了介绍,并提供了丰富的实操示例。希望通过本文的学习,你能够掌握Java并发编程的核心知识,在面试中取得好成绩。同时,在实际工作中,也能够运用这些知识设计和实现高效、稳定的并发系统。
42 0
2025 年 Java 秋招面试必看的 Java 并发编程面试题汇总
文章摘要: 本文系统梳理Java并发编程核心知识点,助力2025年秋招面试。内容涵盖:1)基础概念,包括线程/进程区别、创建线程的3种方式(Thread/Runnable/Callable)、6种线程状态及转换;2)关键机制,对比sleep()与wait()的锁行为差异,解释start()而非run()启动线程的原因;3)工具类与典型应用场景。通过技术原理与代码示例结合的方式,帮助开发者深入理解并发模型、线程同步等核心问题,为高并发系统设计打下坚实基础。(150字)
69 0
Java并发编程中的锁机制与优化策略
【6月更文挑战第17天】在Java并发编程的世界中,锁是维护数据一致性和线程安全的关键。本文将深入探讨Java中的锁机制,包括内置锁、显式锁以及读写锁的原理和使用场景。我们将通过实际案例分析锁的优化策略,如减少锁粒度、使用并发容器以及避免死锁的技巧,旨在帮助开发者提升多线程程序的性能和可靠性。
Java并发编程中的锁优化策略
【5月更文挑战第30天】 在多线程环境下,确保数据的一致性和程序的正确性是至关重要的。Java提供了多种锁机制来管理并发,但不当使用可能导致性能瓶颈或死锁。本文将深入探讨Java中锁的优化策略,包括锁粗化、锁消除、锁降级以及读写锁的使用,以提升并发程序的性能和响应能力。通过实例分析,我们将了解如何在不同场景下选择和应用这些策略,从而在保证线程安全的同时,最小化锁带来的开销。
Java并发编程中的锁优化策略
【5月更文挑战第30天】 在Java并发编程领域,锁机制是实现线程同步的关键手段之一。随着JDK版本的发展,Java虚拟机(JVM)为提高性能和降低延迟,引入了多种锁优化技术。本文将深入探讨Java锁的优化策略,包括偏向锁、轻量级锁以及自旋锁等,旨在帮助开发者更好地理解和应用这些高级特性以提升应用程序的性能。
Java 8中的Stream API:简介与实用指南深入理解Java并发编程:线程安全与锁优化
【5月更文挑战第29天】本文旨在介绍Java 8中引入的Stream API,这是一种用于处理集合的新方法。我们将探讨Stream API的基本概念,以及如何使用它来简化集合操作,提高代码的可读性和效率。 【5月更文挑战第29天】 在Java并发编程中,线程安全和性能优化是两个核心议题。本文将深入探讨如何通过不同的锁机制和同步策略来保证多线程环境下的数据一致性,同时避免常见的并发问题如死锁和竞态条件。文章还将介绍现代Java虚拟机(JVM)针对锁的优化技术,包括锁粗化、锁消除以及轻量级锁等概念,并指导开发者如何合理选择和使用这些技术以提升应用的性能。
Java并发编程中的锁优化策略
【5月更文挑战第27天】在Java多线程开发中,锁是一种常用的同步机制,用于保证共享资源的访问顺序和一致性。然而,不当的锁使用会导致性能瓶颈甚至死锁。本文将探讨Java并发编程中的锁优化策略,包括锁粗化、锁消除、锁细化以及读写锁的使用,旨在帮助开发者提高程序的性能和可靠性。
AI助理
登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问

你好,我是AI助理

可以解答问题、推荐解决方案等