专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java并发工具:ReentrantReadWriteLock

temp10 2025-05-24 16:42:40 java教程 4 ℃ 0 评论

ReentrantReadWriteLock

ReentrantReadWriteLock 是 Java 中 java.util.concurrent.locks 包下的一个可重入的读写锁实现。它允许多个读线程同时访问共享资源,但在写线程访问时,所有其他读和写的线程都会被阻塞。这种机制非常适合读多写少的并发场景。

什么是读写锁?

  • 读锁(Shared Lock):多个线程可以同时持有读锁。
  • 写锁(Exclusive Lock):只能有一个线程持有写锁,并且在写锁存在期间不允许任何读锁。

这比直接使用 ReentrantLock 更高效,因为读操作通常不会改变数据状态,所以允许多个线程并行读取能显著提高并发性能。

Java并发工具:ReentrantReadWriteLock

ReentrantReadWriteLock 的特点

特性

描述

可重入

同一线程可以多次获取读锁或写锁

写锁降级

允许一个线程在持有写锁的情况下再获取读锁,然后释放写锁,实现“锁降级”

不支持读锁升级

不能在持有读锁的情况下获取写锁(会死锁)

公平性可选

支持公平锁与非公平锁模式

条件变量支持

可以为读锁或写锁绑定条件变量(Condition)

使用示例

示例:缓存类中使用 ReentrantReadWriteLock

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

public class Cache {
    private final Map<String, Object> cache = new HashMap<>();
    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    // 读操作使用读锁
    public Object get(String key) {
        lock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " 正在读取: " + key);
            return cache.get(key);
        } finally {
            lock.readLock().unlock();
        }
    }

    // 写操作使用写锁
    public void put(String key, Object value) {
        lock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " 正在写入: " + key);
            cache.put(key, value);
        } finally {
            lock.writeLock().unlock();
        }
    }

    public static void main(String[] args) {
        Cache cache = new Cache();

        // 多线程测试
        Runnable readTask = () -> {
            for (int i = 0; i < 3; i++) {
                cache.get("key" + i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        };

        Runnable writeTask = () -> {
            for (int i = 0; i < 3; i++) {
                cache.put("key" + i, "value" + i);
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        };

        Thread t1 = new Thread(writeTask, "Writer");
        Thread t2 = new Thread(readTask, "Reader1");
        Thread t3 = new Thread(readTask, "Reader2");

        t1.start();
        t2.start();
        t3.start();
    }
}

执行结果

Reader1 正在读取: key0
Reader2 正在读取: key0
Writer 正在写入: key0
Reader1 正在读取: key1
Reader2 正在读取: key1
Writer 正在写入: key1
Reader2 正在读取: key2
Reader1 正在读取: key2
Writer 正在写入: key2

适用场景

场景

说明

缓存系统

读多写少,如本地缓存、配置中心

配置管理

系统配置加载后几乎不变,偶尔更新

数据库连接池

获取连接是读操作,修改配置是写操作

并发统计

统计信息频繁读取,偶尔回收或刷新

注意事项

  1. 不要嵌套加锁顺序错误
  • 避免先加读锁再尝试加写锁,会造成死锁。
  • 推荐写锁降级为读锁。

2.避免锁泄漏

  • 使用 try/finally 确保锁一定会被释放。

3.公平性设置谨慎

  • 默认是非公平模式,适用于大多数高并发场景。
  • 公平模式虽然保证等待顺序,但可能降低吞吐量。

4.锁粒度控制

  • 如果数据结构本身很大,可以考虑分段加锁(类似 ConcurrentHashMap)。

性能对比(简单说明)

模式

读线程数量

写线程数量

性能表现

ReentrantLock

N

M

所有操作串行化,效率低

ReentrantReadWriteLock(读锁)

N

0

并行读取,效率高

ReentrantReadWriteLock(写锁)

0

M

单线程写入

ReentrantReadWriteLock(混合)

>1

1

读写互斥,但读之间并行

总结

功能

方法

获取读锁

readLock().lock()

释放读锁

readLock().unlock()

获取写锁

writeLock().lock()

释放写锁

writeLock().unlock()

是否公平

构造函数传入 true

锁降级

写锁 → 读锁(必须同一线程)

如果正在开发一个需要高性能并发控制的组件(如缓存、数据库代理、配置中心等),强烈推荐使用 ReentrantReadWriteLock 来优化读写性能。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表