1、前言
Guava Cache是一个全内存的本地缓存,它提供了线程安全的实现机制。其简单易用、性能好是本地缓存的不二之选。Guava Cache与ConcurrentMap很相似,但也不完全一样。最基本的区别是ConcurrentMap会一直保存所有添加的元素,直到显式地移除。相对地Guava Cache为了限制内存占用,通常都设定为自动回收元素。在某些场景下,尽管LoadingCache不回收元素,但考虑到其会自动加载缓存,在某些场景也是很有用的。
Guava Cache适用于消耗内存空间来提升速度、某些键会被查询一次以上、缓存中存放的数据总量不会超出内存容量的应用场景。Guava Cache是单个应用运行时的本地缓存,它不把数据存放到文件或外部服务器,如果要得到持久缓存可以尝试使用Redis或者Memcached。
缓存是指暂时在内存中保存某些数据的处理结果,等待下次访问可以快速取出使用。在日常开发中,受限于IO性能或自身业务系统的数据处理能力,获取数据可能非常费时。系统某些数据请求量很大、频繁IO、重复逻辑处理,都会导致系统出现瓶颈。缓存则可以较好解决这样的问题。缓存的作用是将这些数据保存在内存中,当有其它线程或客户端需相同数据时,则可直接从缓存内存块中取出数据。这样,不但可以提高系统的响应时间,也可以节省处理数据的资源消耗,整体上来系统性能会有大大的提升。
2、源码分析
本文以Guava-18.0.jar中源码为例进行阐述。
通常情况下,Guava cache在程序中会以com.google.common.cache.Cache或com.google.common.cache.LoadingCache的形式出现。Cache是接口,LoadingCache也是接口,不过其继承了Cache。
public interface Cache<K, V> {
}
public interface LoadingCache<K, V> extends Cache<K, V>, Function<K, V> {
}
它们共有的方法都存在Cache中,如下所示:
/**
* Returns the value associated with {
@code key} in this cache, or {
@code null} if there is no
*/
@Nullable
V getIfPresent(Object key);
/**
* Returns the value associated with {
@code key} in this cache, obtaining that value from
*/
V get(K key, Callable<? extends V> valueLoader) throws ExecutionException;
/**
* Returns a map of the values associated with {
@code keys} in this cache.
*/
ImmutableMap<K, V> getAllPresent(Iterable<?> keys);
/**
* Associates {
@code value} with {
@code key} in this cache. If the cache previously contained a value associated with {
@code key}, the old value is replaced
*/
void put(K key, V value);
/**
* Copies all of the mappings from the specified map to the cache
*/
void putAll(Map<? extends K,? extends V> m);
/**
* Discards any cached value for key {
@code key}.
*/
void invalidate(Object key);
/**
* Discards any cached values for keys {
@code keys}.
*/
void invalidateAll(Iterable<?> keys);
/**
* Discards all entries in the cache.
*/
void invalidateAll();
/**
* Returns the approximate number of entries in this cache.
*/
long size();
/**
* Returns a current snapshot of this cache's cumulative statistics.
*/
CacheStats stats();
/**
* Returns a view of the entries stored in this cache as a thread-safe map.
*/
ConcurrentMap<K, V> asMap();
/**
* Performs any pending maintenance operations needed by the cache.
*/
void cleanUp();
比较常用的方法有:
V getIfPresent(Object key);
V get(K key, Callable<? extends V> valueLoader) throws ExecutionException;
void put(K key, V value);
void putAll(Map<? extends K,? extends V> m);
Cacahe是接口我们无法使用,Guava中提供了创建者CacheBuilder可以创建一个Cache,实现如下:
Cache<String, Person> caches = CacheBuilder.newBuilder().
// 设置缓存最大容量为100,超过100之后就会按照LRU最近虽少使用算法来移除缓存项
maximumSize(100).
// 设置写缓存后8秒钟过期
expireAfterWrite(8, TimeUnit.SECONDS).
// 设置缓存容器的初始容量为10
initialCapacity(10).
// 当缓存中个数大于设置个数时就会移除
removalListener(new RemovalListener<Object, Object>() {
@Override
public void onRemoval(RemovalNotification<Object, Object> notification) {
System.out.println(
notification.getKey() + " was removed, cause is " + notification.getCause());
}
}).build();
//其中最后带有参数的build实现
//在缓存不存在时通过CacheLoader的实现自动加载缓存
.build(new CacheLoader<Integer, Student>() {
@Override
public Student load(Integer key) throws Exception {
System.out.println("loading student " + key);
Student student = new Student();
student.setId(key);
student.setName("name " + key);
return student;
}
});
CacheBuilder使用了创建者模式,对于内部的成员变量赋值,它都提供了对应的构建方法,代码如下所示:
/**
//直接new了一个CacheBuilder
* Constructs a new {@code CacheBuilder} instance with default settings, including strong keys,
* strong values, and no automatic eviction of any kind.
*/
public static CacheBuilder<Object, Object> newBuilder() {
return new CacheBuilder<Object, Object>();
}
//例如设置Cache缓存最大容量
public CacheBuilder<K, V> maximumSize(long size) {
checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s",
this.maximumSize);
checkState(this.maximumWeight == UNSET_INT, "maximum weight was already set to %s",
this.maximumWeight);
checkState(this.weigher ==