缓存分享(1)——Guava Cache原理及最佳实践

devtools/2024/10/18 14:24:44/

Guava Cache原理及最佳实践

  • 1. Guava Cache是什么
    • 1.1 简介
    • 1.2 核心功能
    • 1.3 适用场景
  • 2. Guava Cache的使用

缓存的种类有很多,需要根据不同的应用场景来选择不同的cache,比如分布式缓存如redis、memcached,还有本地(进程内)缓存如:ehcache、GuavaCache、Caffeine。本篇主要围绕全内存缓存-Guava Cache做一些详细的讲解和分析。

1. Guava Cache是什么

1.1 简介

Guava cache是一个支持高并发的线程安全的本地缓存。多线程情况下也可以安全的访问或者更新Cache。这些都是借鉴了ConcurrentHashMap的结果,不过,guava cache 又有自己的特性 :

"automatic loading of entries into the cache"

即 :当cache中不存在要查找的entry的时候,它会自动执行用户自定义的加载逻辑,加载成功后再将entry存入缓存并返回给用户未过期的entry,如果不存在或者已过期,则需要load,同时为防止多线程并发下重复加载,需要先锁定,获得加载资格的线程(获得锁的线程)创建一个LoadingValueRefrerence并放入map中,其他线程等待结果返回。

1.2 核心功能

  • 自动将entry节点加载进缓存结构中;
  • 缓存的数据超过设置的最大值时,使用LRU算法移除;
  • 具备根据entry节点上次被访问或者写入时间计算它的过期机制;
  • 缓存的key被封装在WeakReference引用内;
  • 缓存的Value被封装在WeakReferenceSoftReference引用内;
  • 统计缓存使用过程中命中率、异常率、未命中率等统计数据。

小结:
Guava Cache说简单点就是一个支持LRU的ConcurrentHashMap,并提供了基于容量,时间和引用的缓存回收方式。(简单概括)

1.3 适用场景

  • 愿意消耗一些内存空间来提升速度(以空间换时间,提升处理速度);
    • 能够预计某些key会被查询一次以上;
    • 缓存中存放的数据总量不会超出内存容量(Guava Cache是单个应用运行时的本地缓存)。
  • 计数器(如可以利用基于时间的过期机制作为限流计数)

2. Guava Cache的使用

GuavaCache使用时主要分二种模式:LoadingCacheCallableCache
核心区别在于:LoadingCache创建时需要有合理的默认方法来加载或计算与键关联的值,CallableCache创建时无需关联固定的CacheLoader使用起来更加灵活。

前置准备:

// RPC调用方法,用于获取数据
private static List<String> rpcCall(String cityId) {// 模仿从数据库中取数据try {switch (cityId) {case "0101":System.out.println("load cityId:" + cityId);return ImmutableList.of("上海", "北京", "广州", "深圳");}} catch (Exception e) {// 记日志}return Collections.EMPTY_LIST;
}

2.1 创建LoadingCache缓存

使用CacheBuilder来构建LoadingCache实例,可以链式调用多个方法来配置缓存的行为。其中CacheLoader可以理解为一个固定的加载器,在创建LoadingCache时指定,然后简单地重写V load(K key) throws Exception方法,就可以达到当检索不存在的时候自动加载数据的效果。

//创建一个LoadingCache,并可以进行一些简单的缓存配置
private static LoadingCache<String, Optional<List<String>> > loadingCache = CacheBuilder.newBuilder()//配置最大容量为100,基于容量进行回收.maximumSize(100)//配置写入后多久使缓存过期-下文会讲述.expireAfterWrite(3, TimeUnit.SECONDS)//配置写入后多久刷新缓存-下文会讲述.refreshAfterWrite(3, TimeUnit.SECONDS)//key使用弱引用-WeakReference.weakKeys()//当Entry被移除时的监听器.removalListener(notification -> System.out.println("notification=" + notification))//创建一个CacheLoader,重写load方法,以实现"当get时缓存不存在,则load,放到缓存并返回的效果.build(new CacheLoader<String, Optional<List<String>>>() {//重点,自动写缓存数据的方法,必须要实现@Overridepublic Optional<List<String>> load(String cityId) throws Exception {return Optional.ofNullable(rpcCall(cityId));}//异步刷新缓存-下文会讲述@Overridepublic ListenableFuture<Optional<List<String>>> reload(String cityId, Optional<List<String>> oldValue) throws Exception {return super.reload(cityId, oldValue);}});// 测试
public static void main(String[] args) {try {System.out.println("load from cache once : " + loadingCache.get("0101").orElse(Lists.newArrayList()));Thread.sleep(4000);System.out.println("load from cache two : " + loadingCache.get("0101").orElse(Lists.newArrayList()));Thread.sleep(2000);System.out.println("load from cache three : " + loadingCache.get("0101").orElse(Lists.newArrayList()));Thread.sleep(2000);System.out.println("load not exist key from cache : " + loadingCache.get("0103").orElse(Lists.newArrayList()));} catch (ExecutionException | InterruptedException e) {//记录日志}
}

执行结果
在这里插入图片描述

2.2 创建CallableCache缓存

在上面的build方法中是可以不用创建CacheLoader的,不管有没有CacheLoader,都是支持Callable的。Callable在get时可以指定,效果跟CacheLoader一样,区别就是两者定义的时间点不一样,Callable更加灵活,可以理解为Callable是对CacheLoader的扩展。CallableCache的方式最大的特点在于可以在get的时候动态的指定load的数据源

//创建一个callableCache,并可以进行一些简单的缓存配置
private static Cache<String, Optional<List<String>>> callableCache = CacheBuilder.newBuilder()//最大容量为100(基于容量进行回收).maximumSize(100)//配置写入后多久使缓存过期-下文会讲述.expireAfterWrite(3, TimeUnit.SECONDS)//key使用弱引用-WeakReference.weakKeys()//当Entry被移除时的监听器.removalListener(notification -> System.out.println("notification=" + notification))//不指定CacheLoader.build();// 测试
public static void main(String[] args) {try {System.out.println("load from callableCache once : " + callableCache.get("0101", () -> Optional.ofNullable(rpcCall("0101"))).orElse(Lists.newArrayList()));Thread.sleep(4000);System.out.println("load from callableCache two : " + callableCache.get("0101", () -> Optional.ofNullable(rpcCall("0101"))).orElse(Lists.newArrayList()));Thread.sleep(2000);System.out.println("load from callableCache three : " + callableCache.get("0101", () -> Optional.ofNullable(rpcCall("0101"))).orElse(Lists.newArrayList()));Thread.sleep(2000);System.out.println("load not exist key from callableCache : " + callableCache.get("0103", () -> Optional.ofNullable(rpcCall("0103"))).orElse(Lists.newArrayList()));} catch (ExecutionException | InterruptedException e) {//记录日志}
}

执行结果:
在这里插入图片描述

后续待补充


http://www.ppmy.cn/devtools/27840.html

相关文章

SSL通信、证书认证原理和失败原因

目录 SSL通信SSL认证原理SSL证书认证失败的原因分析 SSL通信 SSL通信指的是使用SSL&#xff08;Secure Sockets Layer&#xff09;协议进行的加密通讯。SSL是一种标准的安全技术&#xff0c;用于建立一个加密链接&#xff0c;确保从用户的浏览器到服务器之间的数据传输是私密和…

iOS Airpods Pro耳机模式下视频无法播放

最近遇到了一个很奇葩的问题&#xff0c;在iOS16以及17下戴上AirPods Pro耳机就播放失败&#xff0c;只有AirPods Pro如此&#xff0c;AirPods都没问题&#xff0c;百度也是几乎没人遇到&#xff0c;后面经过多方查找&#xff0c;最终定格在Xcode项目配置中&#xff0c;在Build…

AI智能名片商城小程序构建企业级私域的IMC模型:IP、MarTech与Content的深度融合

在数字化营销的新时代&#xff0c;为企业定制开发的AI智能名片B2B2C商城小程序&#xff0c;结合我们丰富的私域运营实践&#xff0c;我们深刻领悟到构建企业级私域的三大核心要素&#xff1a;IP&#xff08;企业人设&#xff09;、MarTech&#xff08;营销技术&#xff09;和Co…

【经典算法】LeetCode31. 下一个排列(Java/C/Python3/GO实现含注释说明,中等)

题目描述 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。例如&#xff0c;arr [1,2,3] &#xff0c;以下这些都可以视作 arr 的排列&#xff1a;[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地&…

GPT-ArcGIS数据处理、空间分析、可视化及多案例综合应用

在数字化和智能化的浪潮中&#xff0c;GIS&#xff08;地理信息系统&#xff09;和GPT&#xff08;生成式预训练模型&#xff09;的结合正日益成为推动科研、城市规划、环境监测等领域发展的关键技术。GIS以其强大的空间数据处理、先进的空间分析工具、灵活的地图制作与可视化能…

笨蛋学C++【C++基础第八弹】

C基础第八弹 1.C文件和流打开文件关闭文件写入文件读取文件读取 & 写入实例文件位置指针 2.C异常处理抛出异常捕获异常处理try抛出的任何类型的异常 C标准的异常定义新的异常 3.C动态内存new和delete运算符new和delete & malloc和free 数组的动态内存分配一维数组二维数…

操作系统总结

文章目录 一、第一章操作系统引论1.操作系统的目标和作用2.操作系统的发展过程3.操作系统的基本特性4.操作系统的主要功能5.操作系统的运行环境6.微内核OS结构 一、第一章操作系统引论 1.操作系统的目标和作用 操作系统的目的&#xff1a; &#xff08;1&#xff09;方便性 &a…

jupyter notebook导出pdf文件显示不了中文

找到文件index.tex.j2&#xff0c;我的在 C:\Users\Administrator\miniconda3\envs\opencv2\share\jupyter\nbconvert\templates\latex 我安装miniconda3并配置opencv2所需要的环境, 配置前 最后&#xff1a;用文本编辑器打开&#xff0c;修改图中article为ctexart&#xf…