导读:本期聚焦于小伙伴创作的《Java中如何使用ReentrantReadWriteLock实现读写锁?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Java中如何使用ReentrantReadWriteLock实现读写锁?》有用,将其分享出去将是对创作者最好的鼓励。

在Java中使用ReentrantReadWriteLock实现读写锁

在多线程场景下,如果共享资源存在大量的读操作,而写操作相对较少,使用普通的互斥锁会导致所有读操作也被串行执行,严重降低系统吞吐量。Java并发包中的ReentrantReadWriteLock提供了读写分离锁的能力,读锁是共享锁,写锁是排他锁,能够在保证线程安全的前提下,大幅提升读多写少场景下的并发性能。

ReentrantReadWriteLock核心特性

了解ReentrantReadWriteLock的核心特性,能帮助我们更合理地使用它:

  • 支持读写分离:读读不互斥、读写互斥、写写互斥,读操作可以并发执行,不会被其他读操作阻塞。
  • 可重入性:同一个线程可以重复获取读锁或写锁,避免死锁问题。
  • 锁降级支持:线程持有写锁的情况下,可以获取读锁,之后释放写锁,完成锁降级,这个特性在需要保证数据一致性的场景下非常实用。
  • 公平与非公平模式:默认是非公平模式,吞吐量更高;也可以构造时指定为公平模式,按照线程等待顺序获取锁,避免线程饥饿。

基础使用步骤

使用ReentrantReadWriteLock实现读写锁的基本流程如下:

  1. 创建ReentrantReadWriteLock实例,根据需求选择公平或非公平模式。
  2. 通过实例的readLock()方法获取读锁,writeLock()方法获取写锁。
  3. 在需要执行读操作的代码块前获取读锁,执行完成后在finally块中释放读锁。
  4. 在需要执行写操作的代码块前获取写锁,执行完成后在finally块中释放写锁。

完整代码示例

下面的示例模拟了一个简单的缓存场景,多个线程并发读取缓存数据,写线程会更新缓存,通过读写锁保证缓存操作的线程安全:

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

public class ReadWriteLockCache {
    // 模拟缓存的Map
    private final Map<String, String> cache = new HashMap<>();
    // 创建非公平模式的读写锁
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    // 获取读锁和写锁
    private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
    private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();

    /**
     * 读取缓存数据,使用读锁
     * @param key 缓存键
     * @return 缓存值,不存在返回null
     */
    public String get(String key) {
        readLock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " 获取读锁,读取key:" + key);
            // 模拟读操作耗时
            Thread.sleep(100);
            return cache.get(key);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return null;
        } finally {
            readLock.unlock();
            System.out.println(Thread.currentThread().getName() + " 释放读锁");
        }
    }

    /**
     * 写入缓存数据,使用写锁
     * @param key 缓存键
     * @param value 缓存值
     */
    public void put(String key, String value) {
        writeLock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " 获取写锁,写入key:" + key + ",value:" + value);
            // 模拟写操作耗时
            Thread.sleep(200);
            cache.put(key, value);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            writeLock.unlock();
            System.out.println(Thread.currentThread().getName() + " 释放写锁");
        }
    }

    /**
     * 锁降级示例:先获取写锁更新数据,再获取读锁读取最新数据,最后释放写锁完成降级
     * @param key 缓存键
     * @param value 新的缓存值
     * @return 更新后的缓存值
     */
    public String updateWithLockDowngrade(String key, String value) {
        writeLock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " 获取写锁,准备更新数据");
            // 先更新数据
            cache.put(key, value);
            // 获取读锁,完成锁降级
            readLock.lock();
            // 此时写锁还未释放,持有写锁+读锁
            String result = cache.get(key);
            // 释放写锁,此时只持有读锁,完成锁降级
            return result;
        } finally {
            // 先释放读锁,再释放写锁(如果写锁还没释放的话,这里先释放读锁)
            readLock.unlock();
            writeLock.unlock();
            System.out.println(Thread.currentThread().getName() + " 完成锁降级,释放所有锁");
        }
    }

    public static void main(String[] args) {
        ReadWriteLockCache cache = new ReadWriteLockCache();
        // 初始化缓存
        cache.put("name", "初始值");

        // 创建多个读线程
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                for (int j = 0; j < 2; j++) {
                    cache.get("name");
                }
            }, "读线程-" + i).start();
        }

        // 创建一个写线程
        new Thread(() -> {
            cache.put("name", "更新后的值");
        }, "写线程").start();

        // 测试锁降级
        new Thread(() -> {
            String result = cache.updateWithLockDowngrade("name", "锁降级后的值");
            System.out.println(Thread.currentThread().getName() + " 锁降级后读取到的值:" + result);
        }, "锁降级线程").start();
    }
}

运行上述代码可以发现,多个读线程可以几乎同时获取读锁执行读取操作,而写线程执行时,所有读线程都会被阻塞,直到写线程释放写锁,符合读写锁的互斥规则。锁降级的示例中,线程在持有写锁的情况下获取读锁,之后释放写锁,既能保证更新后立即读到最新数据,也不会长时间阻塞其他读线程。

使用注意事项

在实际使用ReentrantReadWriteLock时,需要注意以下几点:

  • 锁的获取和释放必须成对出现,建议在finally块中执行释放锁的操作,避免因为异常导致锁无法释放,引发死锁。
  • 不支持锁升级:线程持有读锁的情况下,不能直接获取写锁,会导致当前线程阻塞,甚至死锁,如果需要写操作,应该先释放读锁,再获取写锁。
  • 读锁不支持条件变量:ReentrantReadWriteLock的读锁没有提供newCondition()方法,只有写锁支持条件变量。
  • 根据业务场景选择公平模式:如果业务对线程等待顺序有要求,可以选择公平模式,否则默认的非公平模式吞吐量更高。

Java并发编程ReentrantReadWriteLock读写分离锁锁降级线程安全修改时间:2026-05-24 14:05:44

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。