怎样用读写锁快速实现一个缓存()
1)SDK已经有管程了,不是可以解决所有的并发问题的吗,为什么还要有读写锁?
- 不同的场景下使用不同的锁效果是不一样的,我们的读写锁用在读多写少的场景下那是非常有用的。
- 读写锁并不是java特有的,是通用的一个技术方案。读写锁的话有三个基本原则:
- 同一时刻,允许多个线程去读一个变量
- 同一时刻,只允许一个线程去写变量
- 当有一个线程在写变量的时候,是不能读的
- 同一时刻,允许多个线程去读一个变量
- ReadWriteLock他只是一个接口,他的实现子类是ReentrantReadWriteLock。
- 用的时候直接调用读锁或者写锁readLock()
- 我们定义一个类,这个类呢有k 和 v变量,代表缓存的key和value。有get()读方法,和put()写方法。读的时候上读锁,写的时候上写锁。
class Cache
{
final Mapm =
new HashMap<>();
final ReadWriteLock rwl =
new ReentrantReadWriteLock();
// 读锁
final Lock r = rwl.readLock();
// 写锁
final Lock w = rwl.writeLock();
// 读缓存
V get(K key) {
r.lock();
try { return m.get(key); }
finally { r.unlock(); }
}
// 写缓存
V put(K key, V value) {
w.lock();
try { return m.put(key, v); }
finally { w.unlock(); }
}
}
- 对于数据比较少的,我们直接一次性把数据装进缓存,简单粗暴又高效。
- 对于数据比较多的,要读数据的时候,我们再把它存进缓存里面来。
?
class Cache{
final Mapm =
new HashMap<>();
final ReadWriteLock rwl =
new ReentrantReadWriteLock();
final Lock r = rwl.readLock();
final Lock w = rwl.writeLock();
V get(K key) {
V v = null;
//读缓存
r.lock(); ①
try {
v = m.get(key); ②
} finally{
r.unlock(); ③
}
//缓存中存在,返回
if(v != null) {④
return v;
}
//缓存中不存在,查询数据库
w.lock(); ⑤
try {
//再次验证
//其他线程可能已经查询过数据库
v = m.get(key); ⑥
if(v == null){⑦
//查询数据库
v=省略代码无数
m.put(key, v);
}
} finally{
w.unlock();
}
return v;
}
}
7)为什么要再次进行验证?
- 因为我们的读是并发的,不确定其它线程在这个期间读过没有,为了防止重复读,所以要再次验证。
推荐阅读
- 2021深圳杯A题|常用的统计学指标及其含义
- 使用Vuex实现集中式存储管理应用的所有组件的状态
- 在Windows11使用WSA运行Google|在Windows11使用WSA运行Google play会遇到的问题
- 使用python中的while...else方法
- python中利用break 和continue退出for循环
- R语言用关联规则和聚类模型挖掘处方数据探索药物配伍中的规律
- python中使用马尔可夫决策过程(MDP)动态编程来解决最短路径强化学习问题
- 2022全网最全Android|2022全网最全Android jetpack Compose开发应用指南,从理论基础到项目实战
- 如何利用VuePress和GithubPage搭建一个轻量级博客
- 数据库上云实践(使用Ora2pg进行数据库迁移)