java并发编程

Java 读写锁ReentrantReadWriteLock

2025-03-20  本文已影响0人  饱饱抓住了灵感

一、读写锁核心概念

读写锁是一种并发控制机制,允许多个线程同时读取共享资源,但仅允许一个线程写入资源。适用于读多写少的高并发场景,可显著提升性能。

核心特性

Java实现类

import java.util.concurrent.locks.ReentrantReadWriteLock;

二、基础使用示例

场景:缓存系统(高频读取,低频更新)

import java.util.concurrent.locks.ReentrantReadWriteLock;

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

    public String getValue(String key) {
        lock.readLock().lock(); // 获取读锁
        try {
            return cache.get(key);
        } finally {
            lock.readLock().unlock(); // 释放读锁
        }
    }

    public void putValue(String key, String value) {
        lock.writeLock().lock(); // 获取写锁
        try {
            cache.put(key, value);
        } finally {
            lock.writeLock().unlock(); // 释放写锁
        }
    }
}

输出示例


三、读写锁 vs 互斥锁

特性 读写锁 (ReentrantReadWriteLock) 互斥锁 (synchronized)
读操作并发性 多线程可同时读 仅一个线程可访问
写操作并发性 仅一个线程可写 仅一个线程可访问
适用场景 读多写少(如缓存、配置读取) 写多读少或强一致性场景
性能开销 较低(读操作不阻塞其他读) 较高(所有操作串行化)

四、高级用法

1. 锁降级(Lock Downgrade)

持有写锁的线程可降级为读锁,减少锁竞争:

java

public void updateCacheWithLockDowngrade(String key, String newValue) {
    lock.writeLock().lock(); // 获取写锁
    try {
        // 写操作
        cache.put(key, newValue);

        // 降级为读锁(允许其他读操作)
        lock.readLock().lock();
        lock.writeLock().unlock(); 

        // 继续读操作(如统计缓存大小)
        System.out.println("Cache size: " + cache.size());
    } finally {
        lock.readLock().unlock(); // 释放读锁
    }
}

2. 公平锁与非公平锁

3. 尝试获取锁(带超时)

boolean acquired = lock.readLock().tryLock(10, TimeUnit.SECONDS); // 尝试获取读锁,10秒超时
if (acquired) {
    try {
        // 执行读操作
    } finally {
        lock.readLock().unlock();
    }
} else {
    System.out.println("获取读锁失败");
}

五、注意事项与最佳实践

1. 避免嵌套锁

// ❌ 错误示例:在读锁内调用外部方法(可能获取其他锁)
public void unsafeMethod() {
    lock.readLock().lock();
    try {
        someExternalService.call(); // 可能获取其他锁,导致死锁
    } finally {
        lock.readLock().unlock();
    }
}

// ✅ 正确做法:缩小同步范围
public void safeMethod() {
    lock.readLock().lock();
    try {
        // 仅在此处执行必要操作
    } finally {
        lock.readLock().unlock();
    }
}

2. 使用tryLock()避免死锁

if (lock.writeLock().tryLock(1, TimeUnit.SECONDS)) {
    try {
        // 写操作
    } finally {
        lock.writeLock().unlock();
    }
} else {
    System.out.println("写锁获取失败,稍后重试");
}

3. 锁粒度控制


六、适用场景

  1. 缓存系统:高频读取缓存,低频更新缓存。
  2. 配置管理:动态配置读取多,修改少。
  3. 统计类数据:如计数器(读多写少)。
  4. 大数据分片处理:并行读取不同分片数据,但仅允许一个线程修改元数据。

七、总结

通过合理使用读写锁,可以显著提升高并发系统的性能,但需根据具体场景权衡锁的复杂性与收益。

上一篇 下一篇

猜你喜欢

热点阅读