版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33248299/article/details/78814167
一.CachedData
读写锁一个比较好的例子
- ReentrantReadWriteLock类下的一个CachedData类
- 不过再谈这个之前我们先来说说hibernate的一个知识
- Hibernate中有以下两种获取User实体类对象的方法,它们有什么区别?
User user = session.load(id,User.class);
User user = session.get(id,User.class);
- 第一个方法是不管对象在数据库中是否存在,都会得到一个User对象,这个User对象是一个代理,是一个假的,不是一个真正的User对象,它的内部实际如下
User$Proxy extends User{
private Integer id = id;
User readUser = null;
getName(){ //一个getName的方法
if(readUser == null){ //当readUser为空时
realUser = session.get(id); //送数据库抓取对应id的对象
if(readlUser == null) throw execption //如果不存在就抛异常
}
return realUser.getName();//最后返回
}
}
- 第二个是直接去从数据库中把对象抓取出来,如果不存在,值就是null
总结:没有取到数据,第一个就是抛异常,第二个就是值为null,第一个就是一个缓存的对象
- 类CachedData
class CachedData {// 相当于上面的User$Proxy 用户代理
Object data;
volatile boolean cacheValid;
final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {//处理数据
rwl.readLock().lock();//开读锁
if (!cacheValid) { //是否存在缓存的数据,相等于第一次读数据,数据还不存在 我的代理,不是真正有数据,只是一个假的壳子
// Must release read lock before acquiring write lock
rwl.readLock().unlock();//释放读锁
rwl.writeLock().lock();//开写锁
try {
// Recheck state because another thread might have
// acquired write lock and changed state before we did.
if (!cacheValid) { //为什么这里又要去判断一次?仔细去想一想!!!!
data = ... //如果没有就去查数据
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock();//开读锁
} finally {
rwl.writeLock().unlock(); // Unlock write, still hold read
}
}
try {
use(data);
} finally {
rwl.readLock().unlock(); //不论上面代码会不会出问题都会执行释放读锁
}
}
}
其实它就是一个缓存代理
不要小看缓存代理,有些时候面试题就会遇到喊你写一个缓存系统,下面我们可以仿照上面的来一次个缓存系统
二.缓存系统
1.分析
- 和缓存代理不一样,缓存系统可以装很多个对象
public class CacheDemo {
private Map<String,Object> cache = new HashMap<String,Object>();//用此代替数据库
public static void main(String[] args) {
}
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public Object getData(String key){
Object value = cache.get(key);
if (value == null){ //如果为空就赋值
value = "aaaa";//实际失去queryDB();
}
return value;
}
}
- 因为上面的代码仅仅适用于单线程,如果多线程同时去就需要加上synchronized
public class CacheDemo {
private Map<String,Object> cache = new HashMap<String,Object>();//用此代替数据库
public static void main(String[] args) {
}
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public synchronized Object getData(String key){
Object value = cache.get(key);
if (value == null){ //如果为空就赋值
value = "aaaa";//实际失去queryDB();
}
return value;
}
}
- 但是你根据读写锁来说多个线程来读,不需要互斥;写的时候才需要互斥,所以我们还要改下代码,可以完全仿照CachedData类来完成
public class CacheDemo {
private Map<String,Object> cache = new HashMap<String,Object>();
public static void main(String[] args) {
}
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public Object getData(String key){ //此时是最基础的缓存系统 考虑到多线程就是100分 但是如果你考虑到读写锁问题,就可以得到更高的分数了
rwl.readLock().lock();
Object value = null;
try {
value = cache.get(key);
if (value == null) {
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
if(value == null) {//想想为什么要加这个判断!!!
value = "aaaa";//实际失去queryDB();
}
}finally {
rwl.writeLock().unlock();
}
rwl.readLock().lock();
}
} finally {
rwl.readLock().unlock();
}
return value;
}
}