-
适用性
缓存在很多情况下都是非常有用的。比如,我们需要多次根据给定的输入获取值,而且该值计算或者获取的开销是非常昂贵的。
缓存和ConcurrentMap是非常相像的,但是它们也不完全一样。最根本的区别就是,ConcurrentMap会持有所有添加的对象,直到被显示的移除。而缓存为了限制其内存的使用,通常都会配置成可以自动的将对象移除。在某些情况下即使不自动移除对象也是非常有用的,如LoadingCache它会自动加载缓存对象。
一般,Guava缓存适用于以下几种情况:- 你愿意花费一些内存来换取性能提升;
- 你预测到某些键会多次进行查询;
- 你的缓存数据不超过内存(Guava缓存是单个应用中的本地缓存。它不会将数据存储到文件中,或者外部服务器。如果不适合你,可以考虑一下 Memcached)。
如果你的需要符合上面所说的每一条,那么选择Guava缓存绝对没错。
-
创建guava cache
对于缓存首先需要明确的是:有没有一个方法可以通过给定的键来计算/加载相应的值?如果有,那么可以使用CacheLoader。如果没有这样的方法,或者你想复写缓存的加载方式,但你仍想保留“get-if-absent-compute”语义,你可以在调用get方法时传入一个Callable实例,来达到目的。缓存的对象可以通过Cache.put直接插入,但是自动加载是首选,因为自动加载可以更加容易的判断所有缓存信息的一致性。
Guava Cache有两种创建方式:- cacheLoader
- callable callback
-
LoadingCache 缓存是通过一个CacheLoader来构建缓存。创建一个CacheLoader仅需要实现V load(K key) throws Exception方法即可。下面的范例就是如何创建一个LoadingCache。
LoadingCache<Key,Graph> graphs =CacheBuilder.newBuilder() .maximumSize(1000) .build( newCacheLoader<Key,Graph>(){ publicGraph load(Key key)throwsAnyException{ return createExpensiveGraph(key); } }); try{ return graphs.get(key);
}catch(ExecutionException e){ thrownewOtherException(e.getCause()); }
-
callable callback的实现:
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);
-
guava Cache数据移除:
guava做cache时候数据的移除方式,在guava中数据的移除分为被动移除和主动移除两种。
被动移除数据的方式,guava默认提供了三种方式:
1. 基于大小的移除:看字面意思就知道就是按照缓存的大小来移除,如果即将到达指定的大小,那就会把不常用的键值对从cache中移除。
定义的方式一般为 CacheBuilder.maximumSize(long),还有一种一种可以算权重的方法,个人认为实际使用中不太用到。就这个常用的来看有几个注意点,
其一,这个size指的是cache中的条目数,不是内存大小或是其他;
其二,并不是完全到了指定的size系统才开始移除不常用的数据的,而是接近这个size的时候系统就会开始做移除的动作;
其三,如果一个键值对已经从缓存中被移除了,你再次请求访问的时候,如果cachebuild是使用cacheloader方式的,那依然还是会从cacheloader中再取一次值,如果这样还没有,就会抛出异常
2. 基于时间的移除:guava提供了两个基于时间移除的方法
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) (******)
网友评论