文章目录
1. Cache缓存工具的特点
- 自动加载对象至缓存
- 达到最大size上限后,会根据LRU算法移除对象
- 可通过最近读取或写对象的时长来移除对象
- key自动使用弱引用包装
- value自动使用弱引用or软引用包装
- 对象移除后,会进行提示
- 提供缓存访问的统计信息
2. 构建Cache
2.1 数据对象
public class MyData {
private String name;
private String info;
public MyData(String name, String info) {
this.name = name;
this.info = info;
}
}
2.2 数据获取层Dao
public class MyDao {
/**
* 获取数据需要花费一定时间
*
* @return 数据对象
* @param key
*/
public MyData getData(String key) {
try {
// 模拟获取的时间
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new MyData(key, "Hello World!" + key.hashCode());
}
}
2.3 构建Cache对象(基于size)
// 数据获取层对象
MyDao myDao = new MyDao();
// 移除数据的监听接口 lambda
RemovalListener<String, MyData> removalListener = notification -> System.out.println("remove -> " + notification);
// 缓存加载器,当不存在对应缓存时,调用load()
CacheLoader<String, MyData> cacheLoader = new CacheLoader<String, MyData>() {
public MyData load(String key) throws Exception {
return myDao.getData();
}
};
// 构建Cache
LoadingCache<String, MyData> cache = CacheBuilder.newBuilder()
.maximumSize(100) // 设置缓存size上限,当达到最大size后,将删除最近最少使用的对象(即LRU算法)
.expireAfterWrite(10, TimeUnit.MINUTES) // 设置缓存过期时间
.removalListener(removalListener)
.build(cacheLoader);
2.4 构建Cache对象(基于weight)
LoadingCache<String, MyData> cache = CacheBuilder.newBuilder()
.maximumWeight(10000L) // 当所有对象的weight的和超过此值,就开始使用LRU策略移除对象
.weigher(new Weigher<String, MyData>() {
@Override
public int weigh(String key, MyData value) {
// 设置对象占总weight的多少
// 例如你可以使用对象的内存大小,从而限制Cache最多占用的内存
return key.length() + value.hashCode() % 100;
}
})
.build(cacheLoader);
3. 使用Cache
3.1 从Cache中获取数据
MyData myData = cache.get("key");
System.out.println("myData = " + myData);
3.2 从Cache中获取数据(指定特定获取方式)
MyData myData = cache.get("key", new Callable<MyData>() {
@Override
public MyData call() throws Exception {
Thread.sleep(5000); // 模拟获取花费的时间
return new MyData("key", "Other Method");
}
});
System.out.println("myData = " + myData);
3.3 删除某个key的缓存
cache.invalidate("key");
3.4 向Cache存入数据
cache.put("key", new MyData("key", "google"));
4. Cache的特性
4.1 缓存性能效果
for (int i = 0; i < 100; i++) {
try {
// 前5个值获取比较慢,因为key都是新的,需要重新生成对象
// 后续的数据,因为Cache中已有,所以很快
String key = String.valueOf(i % 5);
MyData myData = cache.get(key);
System.out.println("myData = " + myData);
} catch (ExecutionException e) {
e.printStackTrace();
}
}
4.2 缓存上限size
达到上限size后,会根据LRU策略移除缓存对象,并调用监听接口
Random random = new Random();
for (int i = 0; i < 100; i++) {
try {
String key = String.valueOf(random.nextInt(15));
MyData myData = cache.get(key);
System.out.println("myData = " + myData);
System.out.println("cache.size() = " + cache.size());
} catch (ExecutionException e) {
e.printStackTrace();
}
}
4.3 缓存统计信息
// 构建Cache时,需要添加recordStats()
LoadingCache<String, MyData> cache = CacheBuilder.newBuilder()
.maximumSize(10)
.expireAfterWrite(10, TimeUnit.MINUTES)
.removalListener(removalListener)
.recordStats() // 启动统计
.build(cacheLoader);
Random random = new Random();
for (int i = 0; i < 100; i++) {
try {
String key = String.valueOf(random.nextInt(15));
MyData myData = cache.get(key);
System.out.println("myData = " + myData);
} catch (ExecutionException e) {
e.printStackTrace();
}
}
// 打印统计信息
System.out.println("stats = " + cache.stats());