LoadingCache
个数设置
LoadingCache cache = CacheBuilder.newBuilder()
.initialCapacity(10)//初始化个数
.maximumSize(55)//设置最大个数
.build(new CacheLoader() { //若没有元素,则创建并且放入缓存
@Override
public Object load(Object key) throws Exception {
return key.hashCode();
}
});
注:初始化如何太小,会导致扩容,比较浪费时间,太大浪费内存.
最大数太大,可能导致内存溢出.
重量设置
LoadingCache cache = CacheBuilder.newBuilder()
.maximumWeight(1000) //设置重量,配合weigher使用
.weigher(new Weigher() {
@Override
public int weigh(Object key, Object value) {
return 100;
}
})
.build(new CacheLoader() { //若没有元素,则创建并且放入缓存
@Override
public Object load(Object key) throws Exception {
return key.hashCode();
}
});
weigher相当一杆秤,称每个元数多重,maximumWeight相当总重量.一般用的较少.
过期时间
LoadingCache cache = CacheBuilder.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS) //多长时间未读写后过期
.expireAfterWrite(10, TimeUnit.SECONDS) //多长时间未写后过期
.build(new CacheLoader() { //若没有元素,则创建并且放入缓存
@Override
public Object load(Object key) throws Exception {
return key.hashCode();
}
});
注:元数过期,guava并不会自动回收,它会在写操作时顺带做少量的维护工作,或者偶尔在读操作时做——如果写操作实在太少的话。 这样做的原因在于:如果要自动地持续清理缓存,就必须有一个线程,这个线程会和用户操作竞争共享锁。此外,某些环境下线程创建可能受限制,这样CacheBuilder就不可用了。
相反,我们把选择权交到你手里。如果你的缓存是高吞吐的,那就无需担心缓存的维护和清理等工作。如果你的 缓存只会偶尔有写操作,而你又不想清理工作阻碍了读操作,那么可以创建自己的维护线程,以固定的时间间隔调用Cache.cleanUp()。ScheduledExecutorService可以帮助你很好地实现这样的定时调度。
刷新时间
public static void main(String[] args) throws ExecutionException, InterruptedException {
// guava线程池,用来产生ListenableFuture
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
LoadingCache cache = CacheBuilder.newBuilder()
//指定时间内没有被创建/覆盖,则指定时间过后,再次访问时,会去刷新该缓存,在新值没有到来之前,始终返回旧值
.refreshAfterWrite(2, TimeUnit.SECONDS)
.build(new CacheLoader() { //若没有元素,则创建并且放入缓存
@Override
public Object load(Object key) throws Exception {
return System.currentTimeMillis();
}
//重写reload,使其异步刷新数据
@Override
public ListenableFuture reload(Object key, Object oldValue) throws Exception {
System.out.println("......后台线程池异步刷新:" + key);
return service.submit(new Callable() { //模拟一个需要耗时2s的数据库查询任务
@Override
public Object call() throws Exception {
System.out.println("begin to mock query db...");
Thread.sleep(2000);
System.out.println("success to mock query db...");
return UUID.randomUUID().toString() + key;
}
});
}
});
}
分析:
LoadingCache cache = CacheBuilder.newBuilder()
.softValues()
.weakKeys()
.weakValues()
.build(new CacheLoader() { //若没有元素,则创建并且放入缓存
@Override
public Object load(Object key) throws Exception {
return System.currentTimeMillis();
}
});
强(strong)、软(soft)、弱(weak)请参考: Guava—缓存之Reference
LoadingCache cache = CacheBuilder.newBuilder()
.removalListener(new RemovalListener() {
@Override
public void onRemoval(RemovalNotification notification) {
/**
*RemovalCause 枚举
* 标明是什么情况下 被移除的
*/
RemovalCause cause = notification.getCause();
if (notification.wasEvicted()) { //是否被移除(排除主动删除,和替换)
System.out.println(notification.getKey());
System.out.println(notification.getValue());
}
}
})
.build(new CacheLoader() { //若没有元素,则创建并且放入缓存
@Override
public Object load(Object key) throws Exception {
return System.currentTimeMillis();
}
});
LoadingCache cache = CacheBuilder.newBuilder()
.recordStats()//统计
.build(new CacheLoader() { //若没有元素,则创建并且放入缓存
@Override
public Object load(Object key) throws Exception {
return System.currentTimeMillis();
}
});
CacheStats stats = cache.stats(); //不可变对象
stats.hitCount(); //命中次数
stats.hitRate(); //命中概率
stats.missCount();
stats.missRate();
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
LoadingCache cache = CacheBuilder.newBuilder()
.initialCapacity(10)//初始化个数
.maximumSize(55)//设置最大个数
.maximumWeight(1000) //设置重量,配合weigher使用
.weigher(new Weigher() { //weigher相当一杆秤,称每个元数多重
@Override
public int weigh(String key, Object value) {
return 100;
}
})
.expireAfterAccess(10, TimeUnit.SECONDS) //多长时间未读写后过期
.expireAfterWrite(10, TimeUnit.SECONDS) //多长时间未写后过期
//指定时间内没有被创建/覆盖,则指定时间过后,再次访问时,会去刷新该缓存,在新值没有到来之前,始终返回旧值
.refreshAfterWrite(2, TimeUnit.SECONDS)
.concurrencyLevel(1) //写的并发数
.softValues() //软引用
.weakKeys() //弱引用
.weakValues() //弱引用
.recordStats() //统计的
.removalListener(new RemovalListener() {
@Override
public void onRemoval(RemovalNotification notification) {
/**
*RemovalCause 枚举
* 标明是什么情况下 被移除的
*/
RemovalCause cause = notification.getCause();
if (notification.wasEvicted()) { //是否被移除(排除主动删除,和替换)
System.out.println(notification.getKey() + notification.getValue());
}
}
})
.build(new CacheLoader() { //若没有元素,则创建并且放入缓存
@Override
public Object load(Object key) throws Exception {
return System.currentTimeMillis();
}
@Override
public ListenableFuture reload(Object key, Object oldValue) throws Exception {
System.out.println("......后台线程池异步刷新:" + key);
return service.submit(new Callable() { //模拟一个需要耗时2s的数据库查询任务
@Override
public Object call() throws Exception {
System.out.println("begin to mock query db...");
Thread.sleep(2000);
System.out.println("success to mock query db...");
return UUID.randomUUID().toString() + key;
}
});
}
});
上述算是完整的LoadingCache, 按照实际业务自行配置参数
Spring5放弃掉Guava Cache作为缓存机制,而改用Caffeine作为新的本地Cache的组件。
这个组件目前还没接触到,据说效率很高,待后续…