适用性

  缓存在很多场景下都是相当有用的。例如,计算或检索一个值的代价很高,并且对同样的输入需要不止一次获取值的时候,就应当考虑使用缓存

  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详解的更多相关文章

  1. (转)MyISAM Key Cache详解及优化

    原文:http://huanghualiang.blog.51cto.com/6782683/1372721 一.MyISAM Key Cache详解: 为了最小化磁盘I/O,MyISAM将最频繁访问 ...

  2. HttpContext.Cache 详解

    提到HttpContext.Cache必然会想到Application,他们有什么共性和不同点呢,我们一一道来 相同点: 1.两者都是使用键值对来存储对象 2.两者都是应用程序同生命周期(在cache ...

  3. HTML5应用程序缓存Application Cache详解

    什么是Application Cache HTML5引入了应用程序缓存技术,意味着web应用可进行缓存,并在没有网络的情况下使用,通过创建cache manifest文件,可以轻松的创建离线应用. A ...

  4. 离线应用Application Cache详解

    特点:     1.离线可访问            - 没有网络仍可访问整个应用     2.很小的服务器负载  - 缓存在本地,不需要到服务器请求     3.高速                 ...

  5. spring cache 详解

    Spring使用Cache 从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我 ...

  6. 使用Free命令查看Linux服务器内存使用状况(-/+ buffers/cache详解)

    free命令可选参数 -b,-k,-m,-g show output in bytes, KB, MB, or GB -h human readable output (automatic unit ...

  7. HTML5应用程序缓存Application Cache详解.RP

    什么是Application Cache HTML5引入了应用程序缓存技术,意味着web应用可进行缓存,并在没有网络的情况下使用,通过创建cache manifest文件,可以轻松的创建离线应用. A ...

  8. Oracle内存详解之 Library cache 库缓冲

    Oracle内存详解之 Library cache 库缓冲 2017年11月09日 11:38:39 阅读数:410更多 个人分类: 体系结构 Library cache是Shared pool的一部 ...

  9. Spring Boot 2.x基础教程:进程内缓存的使用与Cache注解详解

    随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一.Spring 3开始提供了强大的基于注解的缓 ...

随机推荐

  1. Kettle基本使用

    Kettle基本使用 Kettle的几个子程序的功能和启动方式 Spoon.bat 图形界面方式启动作业和转换设计器. Pan.bat 命令行方式执行转换. Kitchen.bat   命令行方式执行 ...

  2. maatwebsite lost precision when export long integer data

    Maatwebsite would lost precision when export long integer data, no matter string or int storaged in ...

  3. SpringBoot使用简单缓存

    第一步开启缓存(只要是springboot项目就可以)  数据库连接等相关配置请读者自行实现. 在Application启动类上添加注解 @EnableCaching 开启缓存 @SpringBoot ...

  4. arduino智能循迹小车代码(三个循迹模块)

    #include <Servo.h>int leftMotor1 = 3;int leftMotor2 = 5;int rightMotor1 = 6;int rightMotor2 = ...

  5. Vue基础(五)---- 前端路由

    基本结构: ◆ 1.路由的基本概念与原理 ◆ 2.vue-router的基本使用 ◆ 3.vue-router嵌套路由 ◆ 4.vue-router动态路由匹配 ◆ 5.vue-router命名路由 ...

  6. [ASP.NET Core开发实战]开篇词

    前言 本系列课程文章主要是学习官方文档,再输出自己学习心得,希望对你有所帮助. 课程大纲 本系列课程主要分为三个部分:基础篇.实战篇和部署篇. 希望通过本系列课程,能让大家初步掌握使用ASP.NET ...

  7. Android开发java程序员常用代码,将字符串以逗号分别取出字符串String

    public class StringSplit { public static void main(String[] args) { String sourceStr = "1,2,3,4 ...

  8. iOS打电话功能的简单实现

    小功能简介 iOS中的很多小功能都是非常简单的,几行代码就搞定了,比如打电话.打开网址.发邮件.发短信等 打电话-方法3 创建一个UIWebView来加载URL,拨完后能自动回到原应用 if (_we ...

  9. C++轻量级跨平台文件系统API

    http://en.cppreference.com/w/cpp/experimental/fs https://www.starmessagesoftware.com/cpcclibrary htt ...

  10. hdu6075 2019CCPC网络选拔赛1004 path

    题意:给定一个带权有向图,有q组询问,每次询问在有向图的所有路径中,第k小的路径权值 解题思路:因为k最大只有5e4,考虑暴力搜索出前maxk小的路径并用数组记录权值,然后就可以O(1)查询. 具体实 ...