本地缓存LoadingCache使用【详解】

一、背景

最近来到了新的团队,发现了一个好用的东西-Guava的LoadingCache本地缓存,我们都知道Guava是一个非常好用的工具集合,这次认识到了一个非常好用的本地缓存-LoadingCache。
我们知道缓存有多种类型,比如常见的分布式缓存、Redis缓存等,然而像loadingCache本地缓存是比较轻的,我们都知道内存不贵,在高性能、并发的面前就特别占优势。

二、初识LoadingCache

2.1 LoadingCache简介

我们都知道Guava是一个编程工具类库,其中包含了很多高质量高性能的工具类和方法。其中,LoadingCache是一个带有自动加载功能的缓存,它可以加载缓存中不存在的数据,本质其实是一个键值对(key-value)的缓存,可以通过key获取到对应的缓存值value。

2.2 LoadingCache的核心接口

在Guava中使用LoadingCache时,主要要关注两个接口:CacheLoader和LoadingCache。其中,CacheLoader承担的是将键映射到值的查询逻辑工作,而LoadingCache是CacheLoader的衍生接口。它增加了一些额外的操作,如自动加载、异步加载、缓存刷新等。

首先,定义一下CacheLoader接口及其方法:

public interface CacheLoader {V load(K key) throws Exception;
}

其中K代表键的类型,V代表值的类型。load()方法即为查询逻辑方法,接收一个Key作为参数,返回与该Key相关的Value。如果CacheLoader逻辑中没有命中该Key对应的Value,则将返回null。

接下来是LoadingCache接口及其方法:

public interface LoadingCache extends Cache {V get(K key) throws ExecutionException;ImmutableMap getAll(Iterable keys) throws ExecutionException;void refresh(K key);ConcurrentMap asMap();
}

其中Cache接口是LoadingCache的父接口,它定义了一些基本的缓存操作方法。而LoadingCache则增加了一些自动加载、缓存刷新等操作。

  • get(K key)方法定义了默认的基本缓存操作,如果Cache中不包含该Key对应的Value,将自动调用CacheLoader.load(K key)方法进行自动加载。如果没有定义CacheLoader,将抛出一个UncheckedExecutionException异常。

  • getAll(Iterable<? extends K> keys)则扩展了get(K key),可以同时获取多组Key-Value对的结果。

  • refresh(K key)方法可以对特定Key的Value进行刷新,即调用对应Key的CacheLoader.load(K key)重新加载并替换原值。

  • asMap()方法则返回对应的ConcurrentMap对象,可以使用常规的Map方法来对缓存中的数据进行操作。

三、LoadingCache的缓存策略

LoadingCache提供了基本缓存策略、基于引用缓存策略、基于提醒缓存策略

3.1 LoadingCache的基本缓存策略

Guava提供了两种基本缓存策略,分别为缓存数量大小和基于缓存时间。

3.1.1 基于缓存数量大小

基于大小的缓存是指,当缓存中的Key-Value对数量超出一定的限制时,LoadingCache会自动剔除旧的Key-Value对,以保持缓存大小不超过限制。可以使用maximumSize(long)方法来指定缓存的最大大小,如:

LoadingCache cache = CacheBuilder.newBuilder().maximumSize(100).build(new CacheLoader() {public String load(String key) throws Exception {return key + "->value";}});
3.1.2 基于缓存时间

基于时间的缓存是指,当缓存中的Key-Value对超过限制时间后,LoadingCache会自动剔除该Key-Value对。可以使用expireAfterWrite(long, TimeUnit)方法来指定缓存过期时间。如:

LoadingCache cache = CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES).build(new CacheLoader() {public String load(String key) throws Exception {return key + "->value";}});

3.2 基于引用的缓存策略

基于引用的缓存策略是指,缓存中的Key-Value对的引用关系从而被决定是否从缓存中清除。Guava提供了两种基于引用的缓存策略,分别是弱引用和软引用。

弱引用是指,当Java虚拟机的垃圾回收器扫描到该Key-Value对的Key只被弱引用引用时,将自动从缓存中清除该Key-Value对。可以使用weakKeys()方法启用弱引用:

LoadingCache cache = CacheBuilder.newBuilder().weakKeys().build(new CacheLoader() {public String load(String key) throws Exception {return key + "->value";}});

软引用是指,当Java虚拟机的垃圾回收器扫描到该Key-Value对的Key被软引用引用并且内存不足时,将自动从缓存中清除该Key-Value对。可以使用softValues()方法启用软引用:

LoadingCache cache = CacheBuilder.newBuilder().softValues().build(new CacheLoader() {public String load(String key) throws Exception {return key + "->value";}});

3.3 基于提醒的缓存策略

基于提醒的缓存策略是指,缓存中的Key-Value对在特定条件下会被自动剔除。Guava提供了两种基于提醒的缓存策略,分别是基于写入提醒和基于访问提醒。其中,写入提醒是指,在写入某个Key-Value对时,通知外部任务,以便执行对该Key-Value对的一些处理。访问提醒是指,在特定PerformFunction上访问一个Key-Value对时,通知外部任务,以便记录下该Key-Value对的访问情况。可以使用CacheBuilder提供的removalListener(RemovalListener)方法来启用缓存的提醒策略。

下面是写入提醒的例子:

Cache cache =CacheBuilder.newBuilder().maximumSize(1000).recordStats().removalListener(new RemovalListener() {public void onRemoval(RemovalNotification removalNotification) {System.out.println(removalNotification.getKey() + " was removed, cause is " + removalNotification.getCause());}}).build();

四、线程安全

一个缓存框架的线程安全是非常重要的。Guava的LoadingCache在多线程操作时,是线程安全的。在它的内部实现中使用了ConcurrentHashMap作为容器,对缓存的更新和读取都使用了并发锁机制。

以下是一个LoadingCache的多线程并发示例:

public class LoadingCacheTest {private static final LoadingCache CACHE = CacheBuilder.newBuilder().maximumSize(100).expireAfterWrite(10, TimeUnit.MINUTES).refreshAfterWrite(1, TimeUnit.MINUTES).build(new CacheLoader() {public String load(String key) throws Exception {return key + "->loaded";}});public static void main(String[] args) throws InterruptedException, ExecutionException {new Thread(new Runnable() {public void run() {for (int i = 0; i < 100; i++) {try {System.out.println(Thread.currentThread().getName() + ": " + CACHE.get("key"));TimeUnit.MILLISECONDS.sleep(50L);} catch (Exception e) {e.printStackTrace();}}}}, "Thread-1").start();new Thread(new Runnable() {public void run() {for (int i = 0; i < 50; i++) {try {System.out.println(Thread.currentThread().getName() + ": " + CACHE.get("key2"));TimeUnit.MILLISECONDS.sleep(100L);} catch (Exception e) {e.printStackTrace();}}}}, "Thread-2").start();}
}

五、总结

本文详细介绍了Google Guava中的LoadingCache的实现原理。LoadingCache是一种带有自动加载功能的缓存,可以实现高效的缓存访问和更新。在使用LoadingCache时,要熟悉其核心接口和各种缓存策略,以及线程安全的问题。同时,在实际使用LoadingCache时,需要根据具体的业务场景和数据特点制定相应的缓存策略和CacheLoader处理逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/202792.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Dubbo(二)dubbo调用关系

节点角色说明Provider暴漏服务的额提供方&#xff08;洗浴中心&#xff09;Consumer调用远程服务的消费方&#xff08;客人&#xff09;Registry服务注册与发现的注册中心&#xff08;便民服务中心&#xff0c;所有的饭店娱乐场所都在本中心注册&#xff09;Monitor监控统计服务…

仓库管理应该用ERP系统还是WMS仓储管理系统

WMS仓储管理系统和ERP企业管理系统中的仓储管理模块在功能上具有相似性&#xff0c;但在实际应用中却存在着明显的区别。这些区别对于想要全面构建信息化体系的企业来说&#xff0c;尤其是仓库的系统化管理方面&#xff0c;具有重要的影响。 WMS是一种专注于仓库管理的系统&am…

【go语言开发】loglus日志框架的使用

本文将简单介绍loglus框架的基本使用&#xff0c;并给出demo 文章目录 前言Loglus常见用法自定义日志级别使用字段钩子输出到多个位置使用钩子实现自定义日志处理demo 前言 Logrus 是一个用于 Go 语言的结构化日志框架&#xff0c;它提供了丰富的日志级别、钩子和格式化选项。…

德迅云安全的日常网站安全性措施、以及更多网站安全工具的推荐与使用。

要确保网站的安全性&#xff0c;可以采取以下措施&#xff1a; 更新和维护&#xff1a;定期更新网站的操作系统、应用程序和插件&#xff0c;确保使用的是最新版本&#xff0c;以修复已知的安全漏洞。 强密码策略&#xff1a;使用强密码&#xff0c;包含字母、数字和特殊字符的…

navicat premium 历史版本下载地址

navicat贴心地给大家准备了一致的下载地址&#xff1a; 只是没有把旧版本的链接放出来而已。 链接的格式 &#xff1a; 前缀版本类型语言位数 前缀&#xff1a;http:/download.navicat.com/download/navicat 版本&#xff1a;三位数&#xff0c;前两位是大版本&#xff0c;后…

使用Pytoch实现Opencv warpAffine方法

随着深度学习的不断发展&#xff0c;GPU/NPU的算力也越来越强&#xff0c;对于一些传统CV计算也希望能够直接在GPU/NPU上进行&#xff0c;例如Opencv的warpAffine方法。Opencv的warpAffine的功能主要是做仿射变换&#xff0c;如果不了解仿射变换的请自行了解。由于Pytorch的图像…

MySQL联合查询、最左匹配、范围查询导致失效

服务器版本 客户端&#xff1a;navicat premium16.0.11 联合索引 假设有如下表 联合索引就是同时把多列设成索引&#xff0c;如(empno&#xff0c;ename)在查询的时候就会先按照empno进行查询&#xff0c;再按照ename进行查询其中empno是全局有序&#xff0c;ename是局部有…

flink中处理kafka分区的消息顺序

背景 kafka分区的消息是有序的&#xff0c;那么flink在消费kafka分区的时候消息的顺序是怎么样的呢&#xff1f;还能保持这个有序性吗&#xff0c;本文就来记录下 flink消费kafka分区的顺序性 从上图可知&#xff0c;flink的转换算子比如map&#xff0c;flatMap&#xff0c;f…

IntelliJ IDEA 之初体验

文章目录 第一步&#xff1a;下载与安装 IntelliJ IDEA1&#xff09;官网下载2&#xff09;选择那种安装包3&#xff09;开始下载4&#xff09;解压 第二步&#xff1a;启动 IntelliJ IDEA第三步&#xff1a;创建第一个 Java 项目第四步&#xff1a;运行第一个 Java 程序1&…

代理服务器的IP和端口是什么意思?

代理服务器的地址和端口&#xff1a;基础概念解析 如果我们将其与在互联网发明之前我们的老一辈之间用于交流的经典书信进行类比&#xff0c;那么地址就相当于信封上的寄件人地址&#xff0c;而端口就相当于收信人地址。然而&#xff0c;与传统信件不同&#xff0c;这里需要确切…

【力扣100】 3.最长连续序列

题目链接 class Solution:def longestConsecutive(self, nums: List[int]) -> int:# 先排序&#xff0c;然后遍历元素&#xff0c;r1&#xff0c;然后r在max(temp&#xff0c;r)选择最大的if len(nums)0:return 0# 先set再排序# my_setset(nums)# my_listlist(set(nums))my…

设计一算法,对单链表实现就地逆置

对单链表逆置&#xff0c;要联想到单链表的头插性质 举个例子&#xff1a;现在有一个空链表&#xff0c;我们依次对它进行头插123 那么形成的链表是321&#xff0c;这样就形成了逆置 //单链表就地逆置 //思路&#xff1a;把原表接到一个新表上&#xff0c;然后对原表进行头插 …

【Linux】冯诺依曼体系结构(硬件)、操作系统(软件)、系统调用和库函数 --- 概念篇

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和Linux还有算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 …

logback整合rabbitmq实现消息记录日志

logback.xml文件配置 <!-- 配置rabbitmq的信息&#xff0c;数据取值yml --><springProperty name"rabbitmqHost" source"spring.rabbitmq.host"/><springProperty name"rabbitmqPort" source"spring.rabbitmq.port"/&g…

封装请求头内容格式

// 请求头-内容类型 export const ContentType { JSON: application/json;charsetUTF-8, FORM: application/x-www-form-urlencoded;charsetUTF-8, UPLOAD: multipart/form-data, STREAM: application/octet-stream;charsetUTF-8 } /** * description: 文件上传 * param {*}…

java多人聊天

服务端 package 多人聊天;import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList;…

在windows下编译libiconv库

libiconv是一个基于GNU协议的开源库,主要用于解决多语言编码处理转换等应用问题。在linux系统使用比较方便,但是windows下使用需要进行源码编译。这里我是使用libiconv的1.15版本源码和VS2019默认工具集配置进行编译。 首先需要用VS2019创建一个空项目,根目录为libiconv。 在…

Nero刻录光盘软件-极好用

目录 一、下载Nero 二、软件安装 三、刻录数据 前言 刻录之前准备一张新的光盘&#xff0c;之前一旦使用过&#xff0c;就无法刻录&#xff0c;一定要新的光盘。 一、下载Nero nero官网下载地址&#xff1a;Nero下载 csdn免费下载地址&#xff1a;https://download.csdn.…

springboot引入swagger2

1&#xff0c;pom文件里引入swagger-ui依赖 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.7.0</version></dependency><dependency><groupId>io.spring…