网站首页 > java教程 正文
ReentrantReadWriteLock
ReentrantReadWriteLock 是 Java 中 java.util.concurrent.locks 包下的一个可重入的读写锁实现。它允许多个读线程同时访问共享资源,但在写线程访问时,所有其他读和写的线程都会被阻塞。这种机制非常适合读多写少的并发场景。
什么是读写锁?
- 读锁(Shared Lock):多个线程可以同时持有读锁。
- 写锁(Exclusive Lock):只能有一个线程持有写锁,并且在写锁存在期间不允许任何读锁。
这比直接使用 ReentrantLock 更高效,因为读操作通常不会改变数据状态,所以允许多个线程并行读取能显著提高并发性能。
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
适用场景
场景 | 说明 |
缓存系统 | 读多写少,如本地缓存、配置中心 |
配置管理 | 系统配置加载后几乎不变,偶尔更新 |
数据库连接池 | 获取连接是读操作,修改配置是写操作 |
并发统计 | 统计信息频繁读取,偶尔回收或刷新 |
注意事项
- 不要嵌套加锁顺序错误
- 避免先加读锁再尝试加写锁,会造成死锁。
- 推荐写锁降级为读锁。
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 来优化读写性能。
猜你喜欢
- 2025-05-24 腾讯面试:什么锁比读写锁性能更高?
- 2025-05-24 Linux系统编程—读写锁rwlock
- 2025-05-24 谈谈在Bitcask中用读写锁实现并发控制的性能表现
- 2025-05-24 3个真实案例,彻底吃透读写锁ReentrantReadWriteLock
- 2025-05-24 Redis 应用实践:读写锁进行性能优化
- 2025-05-24 Java多线程编程中的锁机制剖析
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)