缓存是我们日常开发中是必不可少的一种解决性能问题的结构。简单讲,cache 就是为了提升系统性能而开辟的一块内存空间。
缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用。在日常开发的很多场合,由于受限于硬盘IO的性能或者我们自身业务系统的数据处理和获取可能非常费时,当我们发现我们的系统这个数据请求量很大的时候,频繁的IO和频繁的逻辑处理会导致硬盘和CPU资源的瓶颈出现。缓存的作用就是将这些来自不易的数据保存在内存中,当有其他线程或者客户端需要查询相同的数据资源时,直接从缓存的内存块中返回数据,这样不但可以提高系统的响应时间,同时也可以节省对这些数据的处理流程的资源消耗,整体上来说,系统性能会有大大的提升。
缓存在很多系统和架构中都用广泛的应用,例如:
1.CPU缓存
2.操作系统缓存
3.本地缓存
4.分布式缓存
5.HTTP缓存
6.数据库缓存
等等,可以说在计算机和网络领域,缓存无处不在。可以这么说,只要有硬件性能不对等,涉及到网络传输的地方都会有缓存的身影。
Guava Cache是一个全内存的本地缓存实现,它提供了线程安全的实现机制。整体上来说Guava cache 是本地缓存的不二之选,简单易用,性能好。当然如果你希望在分布式系统中使用缓存,那么还是需要Memcache来解决问题。
Guava Cache有两种:
1. CacheLoader
2. Cache
区别在于Cache并不会自动处理加载缓存,定制程度较高。
创建方式:
1. cacheLoader
2. callable callback
通过这两种方法创建的cache,和通常用map来缓存的做法比,有一个明显的特点–两种方法都实现了一种逻辑–从缓存中取key X的值,如果该值已经缓存过了,则返回缓存中的值,如果没有缓存过,可以通过某个方法(也就是业务上返回数据的逻辑)来获取这个值。guava提供的这两种方法的区别在于,cacheloader的定义比较宽泛,是针对整个cache定义的,可以认为是统一的根据key值load value的方法。而callable的方式较为灵活,允许你在get的时候指定。
cacheLoader方式实现实例:
public void TestLoadingCache() throws Exception{
LoadingCache<String,String> cahceBuilder=CacheBuilder
.newBuilder()
.build(new CacheLoader<String, String>(){
@Override
public String load(String key) throws Exception {
String strProValue="hello "+key+"!";
return strProValue;
}
});
System.out.println("jerry value:"+cahceBuilder.apply("jerry"));
System.out.println("jerry value:"+cahceBuilder.get("jerry"));
System.out.println("peida value:"+cahceBuilder.get("peida"));
System.out.println("peida value:"+cahceBuilder.apply("peida"));
System.out.println("lisa value:"+cahceBuilder.apply("lisa"));
cahceBuilder.put("harry", "ssdded");
System.out.println("harry value:"+cahceBuilder.get("harry"));
}
输出:
jerry value:hello jerry!
jerry value:hello jerry!
peida value:hello peida!
peida value:hello peida!
lisa value:hello lisa!
harry value:ssdded
callable callback的实现:
@Test
public void testcallableCache()throws Exception{
Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(1000).build();
String resultVal = cache.get("jerry", new Callable<String>() {
public String call() {
String strProValue="hello "+"jerry"+"!";
return strProValue;
}
});
System.out.println("jerry value : " + resultVal);
resultVal = cache.get("peida", new Callable<String>() {
public String call() {
String strProValue="hello "+"peida"+"!";
return strProValue;
}
});
System.out.println("peida value : " + resultVal);
}
输出:
jerry value : hello jerry!
peida value : hello peida!
cache的常用方法:
回收(Evictions):
1. 大小的设置:CacheBuilder.maximumSize(long) CacheBuilder.weigher(Weigher) CacheBuilder.maxumumWeigher(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(K) 在生成新的value的时候,旧的value依然会被使用。
2. CacheLoader.reload(K, V) 生成新的value过程中允许使用旧的value
3. CacheBuilder.refreshAfterWrite(long, TimeUnit) 超时自动刷新cache
基于泛型的实现:
/**
* 不需要延迟处理(泛型的方式封装)
* @return
*/
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)
.expireAfterWrite(10, TimeUnit.MINUTES)