您的位置:首页 > 产品设计 > UI/UE

Guava CacheBuilder使用说明

2016-08-03 00:00 323 查看
摘要: 结合代码介绍Guava CacheBuilder类以及用CacheBuilder构建的缓存实例具有的特性。

CacheBuilder是Guava用于创建LoadingCache、Cache实例的构建类。可以使用下面的方法来创建一个Cache实例。

LoadingCache<String, JsonObject> cacheDemo = CacheBuilder.newBuilder().concurrencyLevel(5).expireAfterAccess(30, TimeUnit.MINUTES).initialCapacity(100).maximumSize(5000)
.recordStats().removalListener(entry -> {
LOG.info("remove cache! Entry key = " + entry.getKey());
}).build(new CacheLoader<String, JsonObject>() {
@Override
public JsonObject load(String key) throws Exception {
return readEntryFromDb(key);
}
});


Guava CacheBuilder构建的缓存特性

通过CacheBuilder构建的Cache实例具有以下特性:

将数据写入缓存时是原子操作。

当缓存的数据达到最大规模时,会使用“最近最少使用(LRU)”算法来清除缓存数据。

每一条数据还可以基于时间回收,未使用时间超过一定时间后,数据会被回收。

当缓存被清除时,会发送通知告知。

提供访问统计功能。

使用Guava CacheBuilder需要了解的细节

通过CacheBuilder创建缓存实例的数据结构是一个hash table,其性能和特征都类似于ConcurrentHashMap。它实现了LoadingCache的所有方法和Cache接口。调用Cache::asMap接口时,会返回一个 “弱关联属性的iterators”,这意味着当获取了这个ConcurrentMap之后,当前线程操作缓存的结果都会立刻在ConcurrentMap上生效,但是不能确保其他线程修改的缓存数据会映射到已获取ConcurrentMap中。

通常情况下,缓存通过Object对象的equals方法来比对键值。但是当缓存指定成 weakKeys 类型后,键值的对比将会使用 “==”来比对。同样的,当指定为 weakValues 或 softValues 类型后,会使用"=="来比对存储值。

当设置了maximumSize、maximumWeight、expireAfterWrite、expireAfterAccess、weakKeys、weakValues、softValues等参数后,缓存的数据会根据规则自动被清除。

如果设置maximumSize、maximumWeight,在每次修改缓存数据时,都有可能有数据被清除。

如果设置了expireAfterWrite或expireAfterAccess参数,当每个缓存被修改、访问缓存数据或调用Cache::cleanUp方法时某些数据可能会被清除。此时被清除的数据,调用Cache::size时还会被计数,但是已无法被读写。

如果设置了weakKeys、weakValues、softValues,可能会出现某些存储在缓存中的数据被GC回收的情况。这些已经被回收的缓存数据会在缓存被修改、访问缓存、或调用Cache::cleanUp方法时被清除。这些被清除的数据在调用Cache::size时还会被计数,但是已无法读写。

某些缓存的配置会让缓存启动定期维护任务,任务会读写操作后被执行。调用Cache::cleanUp方法时,也会启用缓存维护任务。请勿在用于高吞吐量的缓存中调用Cache::cleanUp方法。当设置了removalListener、expireAfterWrite、expireAfterAccess、weakKeys、weakValues、softValues后,会导致维护任务运行。

由CacheBuilder创建的缓存可以被序列化和反序列化。序列化时会写入所有的配置信息,但是不会写入任何缓存数据信息。

CacheBuilder方法说明

initialCapacity(int initialCapacity)

指定用于缓存的hash table最低总规模。——例如设置了initialCapacity为60,还设置了concurrencyLevel(参阅下文说明)为8。将会把存储的空间分为8块,每块都有一个hash table结构,每个hash table的初始规模为8。如果缓存空间有限,需要预估足够大的初始化空间来缓,避免在数据增长时昂贵的扩展操作(扩展空间会导致深度COPY)。

concurrencyLevel(int concurrencyLevel)

允许同时并发更新操作数。是指对一个缓存中的数据进行更新操作时的并发量。设置这个参数后,允许并发的最大量不一定会严格遵守这个参数。因为数据被分别存储到不同的区块中,而这些数据并不是均匀分布的。在代码实现中,缓存在将会根据这个参数创建对应的ConcurrentMap个数,每一个ConcurrentMap称为一个区块。数据会分别存储到每个ConcurrentMap上,还会有另外一个数据结构来维护所有缓存数据所在的位置。因此,如果将这个参数设置过大,会导致更多时间和空间上的开销(分配了更多的区块,需要额外维护这些区块信息);如果设置过小,会导致在更新操作时,有大量的线程阻塞(更新同一个ConcurrentMap需要等待锁)。

maximumSize(long size)

允许最大的缓存条目数。需要注意的是,在数据条目数达到maximumSize之前,就可能发生数据回收事件。在缓存的数据快要达到规模上限时,缓存就会回收可能不再会使用的数据。

maximumWeight(long weight)

数据清除权重。在缓存的使用中,这个权重的概率很难理解,简单的说就是:每个参数在进入缓存之前都会使用用户自定义的Weigher对象来运算每条数据的权重值。在进行数据释放时,会参考数据的权重值和设定的“maximumWeight”来确定哪条数据需要被回收。声明代码如下:

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.maximumWeight(100000)
.weigher(new Weigher<Key, Graph>() {
public int weigh(Key k, Graph g) {
return g.vertices().size();
}
})
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) { // no checked exception
return createExpensiveGraph(key);
}
});


weakKeys()

将缓存中的key设置成weakKey模式。默认情况下,会使用“强关系”来保存key值。当设置为weakKey时,会使用(==)来匹配key值。在使用weakKey的情况下,数据可能会被GC。数据被GC后,可能仍然会被size方法计数,但是对其执行read或write方法已经无效。

weakValues()

将缓存中的数据设置为weakValues模式。启用weakValue设置时,某些数据会被GC。默认情况下,会使用“强关系”来保存key值。当设置为weakValue时,会使用(==)来匹配value值。数据被GC后,可能仍然会被size方法计数,但是对其执行read或write方法已经无效。

softValues()

将缓存中的数据设置为softValues模式。使用这个模式时,所有的数据都使用SoftReference类对缓存中的数据进行包裹(就是在SoftReference实例中存储真实的数据)。使用SoftReference包裹的数据,会被全局垃圾回收管理器托管,按照LRU的原则来定期GC数据。数据被GC后,可能仍然会被size方法计数,但是对其执行read或write方法已经无效。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Guava Java cache