Guava 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实例具有以下特性:

  1. 将数据写入缓存时是原子操作。
  2. 当缓存的数据达到最大规模时,会使用“最近最少使用(LRU)”算法来清除缓存数据。
  3. 每一条数据还可以基于时间回收,未使用时间超过一定时间后,数据会被回收。
  4. 当缓存被清除时,会发送通知告知。
  5. 提供访问统计功能。

使用Guava CacheBuilder需要了解的细节

  1.  通过CacheBuilder创建缓存实例的数据结构是一个hash table,其性能和特征都类似于ConcurrentHashMap。它实现了LoadingCache的所有方法和Cache接口。调用Cache::asMap接口时,会返回一个 “弱关联属性的iterators”,这意味着当获取了这个ConcurrentMap之后,当前线程操作缓存的结果都会立刻在ConcurrentMap上生效,但是不能确保其他线程修改的缓存数据会映射到已获取ConcurrentMap中。
  2. 通常情况下,缓存通过Object对象的equals方法来比对键值。但是当缓存指定成 weakKeys 类型后,键值的对比将会使用 “==”来比对。同样的,当指定为 weakValues 或 softValues 类型后,会使用"=="来比对存储值。
  3. 当设置了maximumSize、maximumWeight、expireAfterWrite、expireAfterAccess、weakKeys、weakValues、softValues等参数后,缓存的数据会根据规则自动被清除。
  4. 如果设置maximumSize、maximumWeight,在每次修改缓存数据时,都有可能有数据被清除。
  5. 如果设置了expireAfterWrite或expireAfterAccess参数,当每个缓存被修改、访问缓存数据或调用Cache::cleanUp方法时某些数据可能会被清除。此时被清除的数据,调用Cache::size时还会被计数,但是已无法被读写。
  6. 如果设置了weakKeys、weakValues、softValues,可能会出现某些存储在缓存中的数据被GC回收的情况。这些已经被回收的缓存数据会在缓存被修改、访问缓存、或调用Cache::cleanUp方法时被清除。这些被清除的数据在调用Cache::size时还会被计数,但是已无法读写。
  7. 某些缓存的配置会让缓存启动定期维护任务,任务会读写操作后被执行。调用Cache::cleanUp方法时,也会启用缓存维护任务。请勿在用于高吞吐量的缓存中调用Cache::cleanUp方法。当设置了removalListener、expireAfterWrite、expireAfterAccess、weakKeys、weakValues、softValues后,会导致维护任务运行。
  8. 由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方法已经无效。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏容器云生态

shell脚本实例

'使用sed 去除以空格开头的行,第一个sort进行整理输出,uniq -c进行统计,sort -rn进行从大到小排列 # cat cat.ip | awk -...

2646
来自专栏数据之美

线上服务 CPU 100%?一键定位 so easy!

背景 经常做后端服务开发的同学,或多或少都遇到过 CPU 负载特别高的问题。尤其是在周末或大半夜,突然群里有人反馈线上机器负载特别高,不熟悉定位流程和思路的同学...

5138
来自专栏运维

Unix & Linux 大学教程 学习总结

两年前我看这本书时,是一本812页的厚书,现在我总结成了40句话,什么时候成了1句话就好了。

1531
来自专栏程序猿DD

死磕Java并发:J.U.C之Condition

在没有Lock之前,我们使用synchronized来控制同步,配合Object的wait()、notify()系列方法可以实现等待/通知模式。在Java SE...

1145
来自专栏spring源码深度学习

重拾python爬虫之urllib

学习一门技术,总是要踩好多坑,然后收货一大堆疑惑,这么多相似的方式该学哪个呢?外面公司常用的是哪个呢? 就比如python爬虫,可以作为网络请求的方式有四种,...

1312
来自专栏ascii0x03的安全笔记

Linux下ls命令显示符号链接权限为777的探索

Linux下ls命令显示符号链接权限为777的探索                                                ——深入ls、...

1K5
来自专栏芋道源码1024

【死磕Java并发】-----J.U.C之Condition

此篇博客所有源码均来自JDK 1.8 在没有Lock之前,我们使用synchronized来控制同步,配合Object的wait()、notify()系列方法可...

41012
来自专栏CDA数据分析师

学会这几招,轻松掌握Python文件管理

一、Python中的文件管理 文件管理是很多应用程序的基本功能和重要组成部分。Python可以使文件管理极其简单,特别是和其它语言相对比。 以下,Peyton ...

3036
来自专栏钟绍威的专栏

linux常用命令之查阅文件用法选项功能键用法选项DEMO用法选项选项注意选项注意选项注意用法选项

CAT cat – concatenate print files 连续的输出文件内容 用法 cat [-nbA] file 选项 -n line number...

1995
来自专栏风口上的猪的文章

.NET面试题系列[17] - 多线程概念(2)

当我们创建了一个线程后,线程里面主要包括线程内核对象、线程环境块、1M大小的用户模式栈和内核模式栈。

4432

扫码关注云+社区

领取腾讯云代金券