前提:
数据库表 student:
create table student(
id int,
name varchar(15)
);
一.线程不安全版本
import java.util.HashMap;
import java.util.Map;
public class CacheDemo {
//map 用来作缓存模型
private static Map<String, Object> map = new HashMap<String, Object>();
//根据 key 的值,返回其对应的 value
public static Object getValue(String key) {
Object value = map.get(key);
if (value == null) {
int ID=Integer.value(key);
value =//去数据库查询该 key 对应的 value ( select name from student where id=ID;)
map.put(key, value); //将数据放到缓存模型中
}
return value; //map 中存在该 key 对应的值那么则返回
}
}
从上面的代码可以看出,当有 10 个线程同时访问数据库的时候,会出现数据查询的次数也是10次,这样对数据库的访问压力过大,不推荐使用。
二.线程安全版本
import java.util.HashMap;
import java.util.Map;
public class CacheDemo {
// map 用来作缓存模型
private static Map<String, Object> map = new HashMap<String, Object>();
public synchronized static Object getValue(String key) {
Object value = map.get(key);
if (value == null) {
value = //去数据库查询该 key 对应的 value ( select name from student where id=ID;)
map.put(key, value); //将数据放到缓存模型中
}
return value;
}
}
从上面的代码可以看出,在 getValue() 方法上加上 synchronized 后,当有 10 个线程(10 个线程携带的 key 值都一样)都要访问数据库的时候,线程之间只有抢到了锁的线程才可以访问数据库进行数据查询,因此一定程度上减少了数据库访问压力,但是锁的粒度比较大。
三.升级版本
import java.util.HashMap;
import java.util.Map;
public class CacheDemo {
// map 用来作缓存模型
private static Map<String, Object> map = new HashMap<String, Object>();
public static Object getValue(String key) {
Object value = map.get(key);
if(value==null){
synchronized (CacheDemo.class){
if(value==null){
value="abc"; //去数据库查询该 key 对应的 value ( select name from student where id=ID;)
map.put(key,value);//将数据放到缓存模型中
}
}
}
return value;
}
}
从上面的代码可以看出,如果 10 个线程(10 个线程携带的 key 值都一样)访问的数据已经存在于 map 中了,那么就不会出现竞争锁的情况,直接返回 value 即可。但是如果线程访问的数据不存在于 map 中的时候,才会出现竞争锁的情况然后进行数据库的查询,并且只有第一个抢到锁的线程才可以查询数据库,其他的线程拿到锁以后,发现 value 已经不为 null 了,直接返回 value 的值即可。
原文来源:https://blog.youkuaiyun.com/u010452388/article/details/82725299