Guava Cache详解
适用性
缓存在很多场景下都是相当有用的。例如,计算或检索一个值的代价很高,并且对同样的输入需要不止一次获取值的时候,就应当考虑使用缓存
Guava Cache与ConcurrentMap很相似,但也不完全一样。最基本的区别是ConcurrentMap会一直保存所有添加的元素,直到显式地移除。相对地,Guava Cache为了限制内存占用,通常都设定为自动回收元素。在某些场景下,尽管LoadingCache 不回收元素,它也是很有用的,因为它会自动加载缓存
通常来说,Guava Cache适用于:
- 你愿意消耗一些内存空间来提升速度。
- 你预料到某些键会被查询一次以上。
- 缓存中存放的数据总量不会超出内存容量。(Guava Cache是单个应用运行时的本地缓存。它不把数据存放到文件或外部服务器。如果这不符合你的需求,请尝试Redis这类工具)
如果你的场景符合上述的每一条,Guava Cache就适合你。
如果你不需要Cache中的特性,使用ConcurrentHashMap有更好的内存效率——但Cache的大多数特性都很难基于旧有的ConcurrentMap复制,甚至根本不可能做到
代码详解
1 /**
2 * @author LiuHuan
3 * @date 2020-06-17 15:52
4 * @desc Guava Cache学习
5 */
6 public class GuavaCacheTest {
7
8 public static void main(String[] args) throws ExecutionException {
9 GuavaCacheTest test = new GuavaCacheTest();
10 Cache<String, String> cache = test.getGuavaCache();
11 // 放入/覆盖一个缓存
12 cache.put("key", "value");
13 // 获取一个缓存,如果该缓存不存在则返回一个null值
14 cache.getIfPresent("");
15 // 获取缓存,当缓存不存在时,则通Callable进行加载并返回。该操作是原子
16 cache.get("key", () -> loadingValue("key"));
17 // 回收key为k1的缓存
18 cache.invalidate("key");
19 // 使用Map的put方法进行覆盖刷新
20 cache.asMap().put("key", "value");
21 // 使用ConcurrentMap的replace方法进行覆盖刷新
22 cache.asMap().replace("key", "value1");
23 // 使用Map的putAll方法进行批量覆盖刷新
24 Map<String,String> needRefresh = ImmutableMap.of("key1","value1", "key2", "value2");
25 cache.asMap().putAll(needRefresh);
26 // 批量回收key为key1、key2的缓存
27 List<String> needInvalidateKeys = Arrays.asList("key1", "key2");
28 cache.invalidateAll(needInvalidateKeys);
29 // 回收所有缓存
30 cache.invalidateAll();
31
32 // 用来开启Guava Cache的统计功能。统计打开后,Cache.stats()方法会返回CacheStats对象
33 CacheStats stats = cache.stats();
34 // 缓存命中率
35 double hitRate = stats.hitRate();
36 // 加载新值的平均时间,单位为纳秒
37 double averageLoadPenalty = stats.averageLoadPenalty();
38 // 缓存项被回收的总数,不包括显式清除
39 long evictionCount = stats.evictionCount();
40
41 LoadingCache<String, String> loadingCache = test.getGuavaLoadingCache();
42 // loadingCache 在进行刷新时无需显式的传入value
43 loadingCache.refresh("key");
44 }
45
46 /**
47 * 获取GuavaCache实例
48 * @return
49 */
50 public Cache<String, String> getGuavaCache(){
51 // 异步触发监听器
52 RemovalListener<Object, Object> removalListener = RemovalListeners.asynchronous(removal -> {
53 // 如果被显示移除这里为true
54 boolean wasEvicted = removal.wasEvicted();
55 // 移除的原因
56 RemovalCause cause = removal.getCause();
57 }, Executors.newSingleThreadExecutor());
58
59 // 通过CacheBuilder构建一个缓存实例
60 Cache<String, String> cache = CacheBuilder.newBuilder()
61 // 由于Guava的缓存使用了分离锁的机制,扩容的代价非常昂贵,所以合理的初识容量能够减少扩容次数
62 .initialCapacity(100)
63 // 设置缓存的最大条数
64 .maximumSize(100)
65 // maximumWeight逻辑上用来表示一种“权重”,这里与maximumSize冲突,设置一个即可
66 // 这里我们将key和value所占的字节数,作为weight,当cache中所有的“weight”总和达到maximumWeight时,将会触发“剔除策略”
67 .maximumWeight(1024 * 1024)
68 .weigher((Weigher<String, String>)(key, value) -> key.getBytes().length + value.getBytes().length)
69 // 使用弱引用存储键。当键没有其它(强或软)引用时,该缓存可能会被回收
70 .weakKeys()
71 // 使用弱引用存储值。当值没有其它(强或软)引用时,该缓存可能会被回收
72 .weakValues()
73 // 使用软引用存储值。当内存不足并且该值其它强引用引用时,该缓存就会被回收
74 // 通过软/弱引用的回收方式,相当于将缓存回收任务交给了GC,使得缓存的命中率变得十分的不稳定,在非必要的情况下,还是推荐基于数量和容量的回收
75 .softValues()
76 // 设置缓存在写入一分钟后失效
77 .expireAfterWrite(1, TimeUnit.MINUTES)
78 // 设置缓存最后一次访问10分钟之后失效,与session类似。与expireAfterWrite冲突,设置一个即可
79 .expireAfterAccess(Duration.ofMinutes(10))
80 // 开启缓存统计
81 .recordStats()
82 // 设置并发级别为CPU核心数
83 .concurrencyLevel(Runtime.getRuntime().availableProcessors())
84 // 移除监听器,这里是移除缓存时同步调用,会拖慢正常的请求
85 .removalListener(removal -> {
86 // 如果被显示移除这里为true
87 boolean wasEvicted = removal.wasEvicted();
88 // 移除的原因
89 RemovalCause cause = removal.getCause();
90 })
91 // 异步触发监听器
92 .removalListener(removalListener)
93 .build();
94 return cache;
95 }
96
97 /**
98 * 获取GuavaLoadingCache实例,会有默认的缓存加载策略
99 * @return
100 */
101 public LoadingCache<String, String> getGuavaLoadingCache(){
102 // 通过CacheBuilder构建一个缓存实例
103 LoadingCache<String, String> cache = CacheBuilder.newBuilder()
104 // 设置缓存在写入10分钟后,通过CacheLoader的load方法进行刷新
105 .refreshAfterWrite(Duration.ofMinutes(10))
106 .build(new CacheLoader<String, String>() {
107 @Override
108 public String load(String key) throws Exception {
109 // 缓存加载策略
110 return loadingValue(key);
111 }
112
113 });
114 return cache;
115 }
116
117 /**
118 * 缓存加载策略
119 * @param key
120 * @return
121 */
122 private static String loadingValue(String key){
123 return null;
124 };
125
126 }
缓存清理
使用CacheBuilder构建的缓存不会"自动"执行清理和回收工作,也不会在某个缓存项过期后马上清理,也没有诸如此类的清理机制。相反,它会在写操作时顺带做少量的维护工作,如果写操作实在太少的话,偶尔在读操作时做这个操作。这样做的原因在于:如果要自动地持续清理缓存,就必须有一个线程,这个线程会和用户操作竞争共享锁。此外,某些环境下线程创建可能受限制,这样CacheBuilder就不可用了。
如果你的缓存是高吞吐的,那就无需担心缓存的维护和清理等工作。如果你的缓存只会偶尔有写操作,而你又不想清理工作阻碍了读操作,那么可以创建自己的维护线程,以固定的时间间隔调用Cache.cleanUp()。ScheduledExecutorService可以帮助你很好地实现这样的定时调度
Guava Cache详解的更多相关文章
- (转)MyISAM Key Cache详解及优化
原文:http://huanghualiang.blog.51cto.com/6782683/1372721 一.MyISAM Key Cache详解: 为了最小化磁盘I/O,MyISAM将最频繁访问 ...
- HttpContext.Cache 详解
提到HttpContext.Cache必然会想到Application,他们有什么共性和不同点呢,我们一一道来 相同点: 1.两者都是使用键值对来存储对象 2.两者都是应用程序同生命周期(在cache ...
- HTML5应用程序缓存Application Cache详解
什么是Application Cache HTML5引入了应用程序缓存技术,意味着web应用可进行缓存,并在没有网络的情况下使用,通过创建cache manifest文件,可以轻松的创建离线应用. A ...
- 离线应用Application Cache详解
特点: 1.离线可访问 - 没有网络仍可访问整个应用 2.很小的服务器负载 - 缓存在本地,不需要到服务器请求 3.高速 ...
- spring cache 详解
Spring使用Cache 从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我 ...
- 使用Free命令查看Linux服务器内存使用状况(-/+ buffers/cache详解)
free命令可选参数 -b,-k,-m,-g show output in bytes, KB, MB, or GB -h human readable output (automatic unit ...
- HTML5应用程序缓存Application Cache详解.RP
什么是Application Cache HTML5引入了应用程序缓存技术,意味着web应用可进行缓存,并在没有网络的情况下使用,通过创建cache manifest文件,可以轻松的创建离线应用. A ...
- Oracle内存详解之 Library cache 库缓冲
Oracle内存详解之 Library cache 库缓冲 2017年11月09日 11:38:39 阅读数:410更多 个人分类: 体系结构 Library cache是Shared pool的一部 ...
- Spring Boot 2.x基础教程:进程内缓存的使用与Cache注解详解
随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一.Spring 3开始提供了强大的基于注解的缓 ...
随机推荐
- springMVC入门(六)------json交互与RESTFul风格支持
简介 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.由于其简单易用,目前常用来通过AJAX与后台进行交互.springMVC对于接收.发送JSON数据也 ...
- Golang omitempty 的用法
原文链接:https://blog.csdn.net/skh2015java/article/details/90720692omitempty作用是在json数据结构转换时,当该字段的值为该字段类型 ...
- 独立集(bubble) 题解
问题描述 有一天,一个名叫顺旺基的程序员从石头里诞生了.又有一天,他学会了冒泡排序和独立集.在一个图里,独立集就是一个点集,满足任意两个点之间没有边.于是他就想把这两个东西结合在一起.众所周知,独立集 ...
- rlpyt(Deep Reinforcement Learning in PyTorch)
rlpyt: A Research Code Base for Deep Reinforcement Learning in PyTorch Github:https://github.com/ast ...
- Jupyter Notebook 入门指南
https://www.jianshu.com/p/061c6e5c4b0d cmd输入 :jupyter notebook
- Java GUI 图书管理系统
01 概述 一款功能强大的图书馆管理系统,功能齐全,小白/大学生项目实训,学习的不二之选. 02 技术 此系统使用 java awt 实现.java.awt是一个软件包,包含用于创建用户界面和绘制图形 ...
- 哇,ElasticSearch多字段权重排序居然可以这么玩
背景 读者提问:ES 的权重排序有没有示列,参考参考? 刚好之前也稍微接触过,于是写了这篇文章,可以简单参考下. 在很多复杂的业务场景下,排序的规则会比较复杂,单一的降序,升序无法满足日常需求.不过 ...
- Java中一个普通的循环为何从10开始到99连续相乘会得到0?
这是一块非常简单的Java代码片段: public class HelloWorld{ public static void main(String []args){ int product = 1; ...
- mysql 安装卸载自动化脚本
#!/bin/sh #mkdir /root/mysql #tar -xvf mysql-5.7.-.el7.x86_64.rpm-bundle.tar -C /root/mysql #cd /roo ...
- vue 使用 sass 或者 less ( vue-cli 3 )
项目使用 vue-cli 3 在项目中使用 sass npm install sass-loader --save -D cnpm install sass-loader --save -D ...