Guava Cache : LoadingCache是一个本地缓存。
容量回收
、定时回收
和基于引用回收
。定时回收有两种:按照写入时间,最早写入的最先回收;按照访问时间,最早访问的最早回收。超时机制不是精确的。
public static void main(String[] args) throws ExecutionException, InterruptedException{
//缓存接口这里是LoadingCache,LoadingCache在缓存项不存在时可以自动加载缓存
LoadingCache<Integer,Student> studentCache
//CacheBuilder的构造函数是私有的,只能通过其静态方法newBuilder()来获得CacheBuilder的实例
= CacheBuilder.newBuilder()
//设置并发级别为8,并发级别是指可以同时写缓存的线程数
.concurrencyLevel(8)
//设置写缓存后8秒钟过期
.expireAfterWrite(8, TimeUnit.SECONDS)
//设置缓存容器的初始容量为10
.initialCapacity(10)
//设置缓存最大容量为100,超过100之后就会按照LRU最近虽少使用算法来移除缓存项
.maximumSize(100)
//设置要统计缓存的命中率
.recordStats()
//设置缓存的移除通知
.removalListener(new RemovalListener<Object, Object>() {
@Override
public void onRemoval(RemovalNotification<Object, Object> notification) {
System.out.println(notification.getKey() + " was removed, cause is " + notification.getCause());
}
})
//build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
.build(
new CacheLoader<Integer, Student>() {
@Override
public Student load(Integer key) throws Exception {
System.out.println("load student " + key);
Student student = new Student();
student.setId(key);
student.setName("name " + key);
return student;
}
}
);
for (int i=0;i<20;i++) {
//从缓存中得到数据,由于我们没有设置过缓存,所以需要通过CacheLoader加载缓存数据
Student student = studentCache.get(1);
System.out.println(student);
//休眠1秒
TimeUnit.SECONDS.sleep(1);
}
System.out.println("cache stats:");
//最后打印缓存的命中率等 情况
System.out.println(studentCache.stats().toString());
}
输出结果:
cache stats:
CacheStats{hitCount=17, missCount=3, loadSuccessCount=3, loadExceptionCount=0, totalLoadTime=1348802, evictionCount=2}
原因:看看到在20此循环中命中次数是17次,未命中3次,这是因为我们设定缓存的过期时间是写入后的8秒,所以20秒内会失效两次,另外第一次获取时缓存中也是没有值的,所以才会未命中3次,其他则命中。
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Maps;
public class CacheUtil {
private static final Logger logger = LoggerFactory.getLogger(CacheUtil.class);
private static final RedisUtil redisUtil = RedisUtil.getInstance();
/**
* load方式缓存
*
* @param key
* @param value
*/
public static void putByLoad(String key, Object value) {
String valStr = JSON.toJSONString(value);
logger.info("[CacheUtil] putByLoad, key -> " + key + ", value -> " + valStr);
CacheUtil.getInstanceForLoad().put(key, valStr);
redisUtil.set(key, valStr);
}
/**
* load方式读取单个bean
*
* @param key
* @param t
* @return
* @throws Exception
*/
public static <T> T getObjectByLoad(String key, Class<T> t) {
if (key == null)
return null;
String object = null;
try {
object = CacheUtil.getInstanceForLoad().get(key);
logger.info("[CacheUtil] get from cache, key -> " + key + ", value -> " + object);
} catch (Exception e) {
logger.error("[CacheUtil] getByLoad error -> " + e);
}
if (object == null)
return null;
return (T) JSON.parseObject(object, t);
}
/**
* load方式读取list
*
* @param key
* @param t
* @return
*/
public static <T> List<T> getListByLoad(String key, Class<T> t) {
if (key == null)
return null;
String object = null;
try {
object = CacheUtil.getInstanceForLoad().get(key);
} catch (Exception e) {
logger.error("[CacheUtil] getByLoad error -> " + e);
}
if (object == null)
return null;
return JSON.parseArray(object, t);
}
/**
* load方式读取map
*
* @param key
* @param t
* @return
*/
public static <T> Map<String, T> getMapByLoad(String key, Class<T> t) {
if (key == null)
return null;
String object = null;
try {
object = CacheUtil.getInstanceForLoad().get(key);
logger.info("[CacheUtil] get from cache, key -> " + key + ", value -> " + object);
} catch (Exception e) {
logger.error("[CacheUtil] getByLoad error -> " + e);
}
if (object == null)
return null;
Map<String, T> map = JSONObject.parseObject(object, new TypeReference<Map<String, T>>() {
});
for (String k : map.keySet()) {
T o = JSON.parseObject(map.get(k).toString(), t);
map.put(k, o);
}
return map;
}
/**
* map方式缓存
*
* @param key
* @param value
*/
public static void putByMap(String key, Object value) {
CacheUtil.getInstanceForMap().put(key, JSON.toJSONString(value));
}
/**
* map方式读取
*
* @param key
* @param t
* @return
*/
public static <T> T getByMap(String key, Class<T> t) {
Object object = CacheUtil.getInstanceForMap().getIfPresent(key);
if (object == null)
return null;
return (T) JSON.parseObject((String) object, t);
}
public static LoadingCache<String, String> getInstanceForLoad() {
return SingleTonForLoad.cahceBuilder;
}
private static class SingleTonForLoad {
private static LoadingCache<String, String> cahceBuilder = CacheBuilder.newBuilder()
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
redisUtil.expire(key, 0);
String re = redisUtil.get(key);
logger.info("[CacheUtil] get from redis, key -> " + key + ", value -> " + re);
return re;
}
});
}
public static Cache<String, Object> getInstanceForMap() {
return SingleTonForMap.cache;
}
private static class SingleTonForMap {
private static Cache<String, Object> cache = CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES)
.build();
}
public static void main(String[] args) {
Map<String, CompetitionBean> map1 = Maps.newHashMap();
CompetitionBean bean1 = new CompetitionBean();
bean1.setCategory("足球");
map1.put("1", bean1);
CacheUtil.putByLoad("a", map1);
System.err.println(JSON.toJSONString(CacheUtil.getMapByLoad("a", CompetitionBean.class)));
Map<String, CompetitionBean> map2 = Maps.newHashMap();
CompetitionBean bean2 = new CompetitionBean();
bean2.setCategory("篮球");
map2.put("2", bean2);
CacheUtil.putByLoad("a", map2);
System.err.println(JSON.toJSONString(CacheUtil.getMapByLoad("a", CompetitionBean.class)));
}
}