php中文网 | cnphp.com

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 458|回复: 0

怎样用读写锁快速实现一个缓存?

[复制链接]

3

主题

16

帖子

279

积分

VIP会员

Rank: 7Rank: 7Rank: 7

UID
2
威望
0
积分
263
贡献
0
注册时间
2021-4-15
最后登录
2022-3-28
在线时间
4 小时
发表于 2022-3-28 18:10:32 | 显示全部楼层 |阅读模式
1)SDK已经有管程了,不是可以解决所有的并发问题的吗,为什么还要有读写锁?

不同的场景下使用不同的锁效果是不一样的,我们的读写锁用在读多写少的场景下那是非常有用的。

2)读写锁是我们JAVA特有的吗?他有什么原则?

读写锁并不是java特有的,是通用的一个技术方案。读写锁的话有三个基本原则:

同一时刻,允许多个线程去读一个变量

同一时刻,只允许一个线程去写变量

当有一个线程在写变量的时候,是不能读的

3)读写锁在java中是怎样实现的,怎样使用?

ReadWriteLock他只是一个接口,他的实现子类是ReentrantReadWriteLock。

用的时候直接调用读锁或者写锁readLock()

4)既然说了读写锁适合我们缓存的场景下的使用,那读写锁怎样快速的实现一个缓存呢?

我们定义一个类,这个类呢有k 和 v变量,代表缓存的key和value。有get()读方法,和put()写方法。读的时候上读锁,写的时候上写锁。
[mw_shl_code=applescript,true]class Cache<K,V> {
   final Map<K, V> m =
     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(); }
   }
}[/mw_shl_code]
5)实现缓存,会存在数据初始化的问题,那么我们缓存里面的数据该怎样初始化呢?

对于数据比较少的,我们直接一次性把数据装进缓存,简单粗暴又高效。

对于数据比较多的,要读数据的时候,我们再把它存进缓存里面来。

6)上面实现初始化缓存数据的的方法中,第二种代码是怎样实现的?
[mw_shl_code=applescript,true]class Cache<K,V> {
   final Map<K, V> m =
     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;
   }
}[/mw_shl_code]
7)为什么要再次进行验证?

因为我们的读是并发的,不确定其它线程在这个期间读过没有,为了防止重复读,所以要再次验证。

注意:我们的读写锁是可以升级和降级的。但是java中是不可以升级的,升级的话会造成死锁的现象发生。





上一篇:解决Hadoop集群hdfs无法启动DataNode的问题
下一篇:Android BLE 蓝牙开发——扫码枪基于BLESSED
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|php中文网 | cnphp.com ( 赣ICP备2021002321号-2 )51LA统计

GMT+8, 2024-4-29 20:26 , Processed in 0.194736 second(s), 31 queries , Gzip On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

申明:本站所有资源皆搜集自网络,相关版权归版权持有人所有,如有侵权,请电邮(fiorkn@foxmail.com)告之,本站会尽快删除。

快速回复 返回顶部 返回列表