Cache 相关参数说明
1、大小:CacheBuilder.maxmumSize(long) CacheBuilder.weigher(Weigher) CacheBuilder.maxmumWeigher(long) 2、时间: expireAfterAccess(long,TimeUnit) expireAfterWrite(long,TimeUnit) 3、引用: CacheBuilder.weakKeys() CacheBuilder.weakValues() CacheBuilder.softValues() 4、删除: invalidate(key) invalidateAll(keys) invalidateAll() 5、删除监听器: CacheBuilder.removalListener(RemovalListener) refresh(刷新) 机制: 1、LoadingCache.refresh(key) 在生成新的value的时候,旧的value依然会使用 2、CacheLoader.reload(K,V) 生成新的value过程中仍然允许使用旧的value 3、CacheBuilder.refreshAfterWrite(long,TimeUnit)自动刷新cache
/*
Guava Cache 是一个全内存的本地缓存实现,它提供了线程安全的实现机制。(简单易用,性能好)
Guava Cache 有两种创建方式:
CacheLoader
Callable
*/
@Test
public void testLoadingCache() throws ExecutionException {
/*
CacheLoader 的定义比较宽泛,是针对整个cache而言的,可以认为是 统一的根据key值load value的方法
*/
LoadingCache<String,String> cacheBuilder = CacheBuilder.newBuilder().build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
String strProValue = "hello " + key + "!";
return strProValue;
}
});
// cacheBuilder.apply("key"); --> 存值 : 会返回 重写的load方法里面的值
System.out.println(cacheBuilder.apply("java1"));
// cacheBuilder.get("key") --> 取值 get 方法可以实现,取值和存值, 如果 Get方法未取到值 会将其存入到cache中
System.out.println(cacheBuilder.get("java"));
}
@Test
public void testCallAbleCache() throws ExecutionException {
/*
Callable的方式比较灵活,允许在get的时候指定
*/
Cache<String,String> cache = CacheBuilder.newBuilder().maximumSize(1000).build();
String resultValue = cache.get("Java", new Callable<String>() {
public String call() throws Exception {
String strProValue = "hello" + "Java" + "!";
return strProValue;
}
});
// put 方法 存值, get 方法同理,有值取值 没值存值取值
System.out.println(resultValue);
}
从LoadingCache查询的方法是使用get(key)方法。这个方法会返回已经缓存的值,也会使用CacheLoader向缓存中增加新值。要注意的是,调用get()方法时,可能会抛出ExecutionException异常。
数据移除
Guava Cache中的数据移除分为主要移除和被动移除
被动移除,guava提供三种方式:
1、基于大小的移除(maxmumSize(long)):按照缓存的大小来移除数据,还有一个中按照权重来,但是不常使用
要注意的是 maxmumSize(long) 参数代表的是缓存的条数,其次并不是到了指定的size之后才会移除数据,而是在接近size大小的时候进行移除,另外如果一个键值对已经从缓存中被移除了,你再次请求访问的时候,如果cachebuild是使用cacheloader方式的,那依然还是会从cacheloader中再取一次值,如果这样还没有,就会抛出异常
2、基于时间移除
expireAfterAccess(long,TimeUnit) 某个键访问过了多少时间之后移除
expireAfterWrite(long,TimeUnit)某个键值对被创建或者被替换后多少时间后移除
3、基于引用移除
主要是基于java的垃圾回收机制,根据键或者值的引用关系决定移除
主动移除:
1、单独删除:Cache.invalidate(key)
2、批量删除:Cache.invalidateAll(keys)
3、移除所有:Cache.invalidateAll()
如果需要在移除数据的时候有所动作还可以定义Removal Listener,但是有点需要注意的是默认Removal Listener中的行为是和移除动作同步执行的,如果需要改成异步形式,可以考虑使用RemovalListeners.asynchronous(RemovalListener, Executor)
使用CacheBuilder构建的缓存不会”自动”执行清理和回收工作,也不会在某个缓存项过期后马上清理,也没有诸如此类的清理机制。相反,它会在写操作时顺带做少量的维护工作,或者偶尔在读操作时做——如果写操作实在太少的话。
这样做的原因在于:如果要自动地持续清理缓存,就必须有一个线程,这个线程会和用户操作竞争共享锁。此外,某些环境下线程创建可能受限制,这样CacheBuilder就不可用了。
/**
* 不需要延迟处理(泛型的方式封装)
*/
public <K , V> LoadingCache<K , V> cached(CacheLoader<K , V> cacheLoader){
LoadingCache<K, V> cache = CacheBuilder
.newBuilder()
.maximumSize(2)
.weakKeys()
.softValues()
.refreshAfterWrite(120, TimeUnit.SECONDS)
.expireAfterAccess(10, TimeUnit.SECONDS)
.removalListener(new RemovalListener<K, V>() {
@Override
public void onRemoval(RemovalNotification<K, V> removalNotification) {
/*
通过CacheBuilder.removalListener(RmovalListener),可以声明一个监听器,以便缓存项被移除时
做一些额外操作。缓存项被移除时,RemovalListener会获取移除通知【RemovalNotification】,
其中 包含移除原因[RemovalCause]、键和值
*/
System.out.println(removalNotification.getKey() + ",已被移除!");
}
})
.build(cacheLoader);
return cache;
}
/**
* 通过key获取value
* 调用方式 commonCache.get(key); return string;
*/
public LoadingCache<String,String> commonCache(final String key){
LoadingCache<String, String> commonCache = cached(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
return "hello" + key + "!";
}
});
return commonCache;
}
@Test
public void testCache() throws ExecutionException {
LoadingCache<String, String> cache = commonCache("java");
System.out.println(cache.get("java"));
cache.apply("python");
System.out.println(cache.get("python"));
cache.apply("c++");
System.out.println(cache.get("c++"));
}
private static Cache<String, String> cacheFormCallable = null;
/**
* 对需要延迟处理的可以采用这个机制;(泛型的方式封装)
* @param <K>
* @param <V>
* @return V
* @throws Exception
*/
public static <K, V> Cache<K, V> callableCached(){
Cache<K, V> cache = CacheBuilder
.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
return cache;
}
private String getCallableCache(final String userName){
try{
return cacheFormCallable.get(userName, new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println(userName + "from db");
return "我是 " + userName;
}
});
} catch (ExecutionException e) {
e.printStackTrace();
return null;
}
}
// Callable 只有在缓存不存在时,才会调用,比如第二次调用getCallableCache(u1name) 直接返回缓存中的值
@Test
public void testCallableCache(){
final String u1name = "java";
final String u2name = "python";
final String u3name = "c";
cacheFormCallable = callableCached();
System.out.println(getCallableCache(u1name));
System.out.println(getCallableCache(u2name));
System.out.println(getCallableCache(u3name));
System.out.println(getCallableCache(u1name));
}