caffeine和google-guava cache缓存使用详解和源码介绍

google-guava cache

1.pom引入其依赖

<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>20.0</version>
		</dependency>

       

2.具体使用

com.google.common.cache.LoadingCache<String, String> googleCache = CacheBuilder.newBuilder()
            //最大容量为100(基于容量进行回收)
            .maximumSize(100)
            //配置写入后多久使缓存过期-下文会讲述
            .expireAfterWrite(20, TimeUnit.SECONDS)
            //配置写入后多久刷新缓存-下文会讲述
            .refreshAfterWrite(10, TimeUnit.SECONDS)
            .build(new CacheLoader<String, String>() {
                @Override
                public String load(String s) throws Exception {
                    log.info("加载数据");
                    Thread.sleep(5000);
                    return s + System.currentTimeMillis();
                }
            });
//
//            .build(CacheLoader.asyncReloading(new CacheLoader<String, String>() {
//                @Override
//                public String load(String s) throws Exception {
//                    log.info("异步加载数据");
//                    Thread.sleep(5000);
//                    return s + System.currentTimeMillis();
//                }
//            }, executorService));

使用 caffeineCache.get("key")获取缓存值

3.相关参数说明

expireAfterWrite:缓存写入之后过期时间。缓存过期之后再get时会调用load方法加载数据,此时会阻塞当前主线程,如果当前有大量线程get缓存都会被阻塞会对数据库和系统造成压力,这也就是我们常说的“缓存击穿”。

maximumSize:最大缓存容量,基于容量进行回收缓存数据

refreshAfterWrite:缓存刷新时间。缓存过期之后再get只会当前主线程会阻塞,其他线程会返回旧的缓存值。若是也不想阻塞当前主线程,可以重写reload方法,用线程池后台异步加载数据(默认的reload方法其实就是同步调用的load方法,所有需要我们自己重写reload方法,在重写的reload方法种使用线程池去加载数据,下文有简单的代码写法)

4.存取缓存流程

guava cahe的缓存淘汰是在get操作中处理的

1.当缓存不存在此key的缓存时,所有线程阻塞住,当第一个线程写入缓存之后,其他线程获取到缓存值并继续执行

2.如果此key缓存值过期(>expireAfterWrite).则情况同一,只有当第一个线程写入缓存之后,后面线程才继续执行

3.此key的缓存没有过期,会判断是否需要刷新(是否>refreshAfterWrite),若是需要刷新会调用reload方法,第一个线程会阻塞住,后面线程会返回旧的缓存值,若是不阻塞线程只需要重写reload方法,在reload方法中使用线程池去加载数据

5.异步刷新缓存

 ExecutorService executorService = Executors.newFixedThreadPool(10);
        LoadingCache<Long, String> cache
                // CacheBuilder的构造函数是私有的,只能通过其静态方法newBuilder()来获得CacheBuilder的实例
                = CacheBuilder.newBuilder()
                // 设置并发级别为3,并发级别是指可以同时写缓存的线程数
                .concurrencyLevel(3)
                // 过期
                .refreshAfterWrite(5, TimeUnit.SECONDS)
                // 初始容量
                .initialCapacity(1000)
                // 最大容量,超过LRU
                .maximumSize(2000).build(new CacheLoader<Long, String>() {

                    @Override
                    @Nonnull
                    public String load(@Nonnull Long key) throws Exception {
                        Thread.sleep(1000);
                        return DATE_FORMATER.format(Instant.now());
                    }

                    @Override
                    @Nonnull
                    public ListenableFuture<String> reload(@Nonnull Long key, @Nonnull String oldValue) throws Exception {
                        ListenableFutureTask<String> futureTask = ListenableFutureTask.create(() -> {
                            Thread.sleep(1000);
                            return DATE_FORMATER.format(Instant.now());
                        });
                        executorService.submit(futureTask);
                        return futureTask;
                    }
                });

更加简单优雅的写法

  com.google.common.cache.LoadingCache<String, String> googleCache = CacheBuilder.newBuilder()
            //最大容量为100(基于容量进行回收)
            .maximumSize(100)
            //配置写入后多久使缓存过期-下文会讲述
            .expireAfterWrite(20, TimeUnit.SECONDS)
            //配置写入后多久刷新缓存-下文会讲述
            .refreshAfterWrite(10, TimeUnit.SECONDS)
//            .build(new CacheLoader<String, String>() {
//                @Override
//                public String load(String s) throws Exception {
//                    log.info("加载数据");
//                    Thread.sleep(5000);
//                    return s + System.currentTimeMillis();
//                }
//            });

            .build(CacheLoader.asyncReloading(new CacheLoader<String, String>() {
                @Override
                public String load(String s) throws Exception {
                    log.info("异步加载数据");
                    Thread.sleep(5000);
                    return s + System.currentTimeMillis();
                }
            }, executorService));

6.异步加载验证

未重写reload方法

 重写reload方法之后

最佳配置实践

一般配置expireAfterWrite和refreshAfterWrite,refreshAfterWrite<expireAfterWrite

这个设置是因为,如果长时间没有访问缓存,可以保证 expire 后可以取到最新的值,而不是因为 refresh 取到旧值。expireAfterWrite就是到那个时间强制刷新成新值,若是不配置,过了很长时间之后,只配置refreshAfterWrite,这样就可能refresh的时候,其他线程还是返回的旧值(若是重写了reload方法,当前线程也是返回的旧值,因为是异步加载的数据)。

关于guava cache源码分析,可以参考这篇文章

Guava Cache实现原理及最佳实践 | Alben's home

caffeine

pom引入其依赖

<dependency>
			<groupId>com.github.ben-manes.caffeine</groupId>
			<artifactId>caffeine</artifactId>
			<version>2.9.3</version>
		</dependency>

 2.具体使用

   com.github.benmanes.caffeine.cache.LoadingCache<String, String> caffeineCache = Caffeine.newBuilder()
            .maximumSize(5)
            .expireAfterWrite(20, TimeUnit.SECONDS)
            .refreshAfterWrite(10, TimeUnit.SECONDS)
            .build(key -> {
                log.info("加载数据");
                // 加载时,睡眠一秒
                Thread.sleep(5000);
                return key + System.currentTimeMillis();
            });

caffeine基本配置和guava cache一致,她对guava cache的存取效率和淘汰机制做了优化,提高了缓存命中率,caffeine默认是线程池异步refresh加载数据,不需要像guava cache一样重写reload方法

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode题集训 sql

目录 背景步骤175组合两个表&#xff08;多表联查&#xff09;176 177 第n高的薪水&#xff08;Distinct关键字 排序&#xff09;178分数排名 &#xff08;排序 order over关键字&#xff09;179 连续出现的数字 &#xff08;模拟多张表联查&#xff09;181. 超过经理收入的员工…

TCP/IP协议是什么?

78. TCP/IP协议是什么&#xff1f; TCP/IP协议是一组用于互联网通信的网络协议&#xff0c;它定义了数据在网络中的传输方式和规则。作为前端工程师&#xff0c;了解TCP/IP协议对于理解网络通信原理和调试网络问题非常重要。本篇文章将介绍TCP/IP协议的概念、主要组成部分和工…

Elasticsearch:使用 SIMD 指令加速向量搜索

作者&#xff1a;Chris Hegarty, Elastic Principal Engineer, Lucene PMC 翻译&#xff1a;杰瑞朱 多年来&#xff0c;Java 平台上运行的代码一直受益于自动向量化 —— HotSpot C2 编译器中的 superword 优化&#xff0c;将多个标量操作打包到 SIMD&#xff08;单指令多数据…

Git:git merge和git rebase的区别

分支合并 git merge是用来合并两个分支的。比如&#xff1a;将 b 分支合并到当前分支。同样git rebase b&#xff0c;也是把 b 分支合并到当前分支。他们的 「原理」如下&#xff1a; 假设你现在基于远程分支"origin"&#xff0c;创建一个叫"mywork"的分支…

【react全家桶学习】react的 (新/旧) 生命周期(重点)

目录 生命周期&#xff08;旧&#xff09; 挂载时的生命周期 constructor&#xff08;props&#xff09; componentWillMount&#xff08;&#xff09;-------------新生命周期已替换 render&#xff08;&#xff09; componentDidMount&#xff08;&#xff09;--- 组件…

PACS/RIS医学影像管理系统源码 提供先进图像处理和算法

PACS&#xff08;医学影像存档与通信系统&#xff09;主要应用于医学影像的存储、传输和显示。它可以使医生突破胶片的局限&#xff0c;对病人的影像进行全方位的处理和观察&#xff0c;以便得出更准确的诊断。同时&#xff0c;PACS可以节省大量的胶片&#xff0c;降低成本。医…

flex布局瀑布流占位两边对齐不对称

.page{display: flex;justify-content: space-between;flex-wrap: wrap; }.page:after {content: ;width: 400px; // 也可以 flex:1}

jmeter:BeanShell预处理程序获取/设置/引用变量

BeanShell预处理程序 1、局部变量 获取局部变量&#xff1a;vars.get("变量名") 设置局部变量&#xff1a;vars.put("变量名",变量值) 调用 ${变量名} 2、全局变量 获取局部变量&#xff1a;props.get("变量名") 设置局部变量&#xff1a…

KNIME工作流和节点比较功能

KNIME工作流和节点比较功能是一个在 << KNIME 视觉化数据分析 >> 中没有讲到的知识点。 KNIME工作流和节点比较功能在以下几种情况下非常有用&#xff1a; 版本控制&#xff1a;此功能可以跟踪工作流和节点中的更改。如果需要返回到之前的工作流或节点版本&#xf…

Vscode platformio Arduino开发STM32,点灯+串口调试

1.工具 USB-TTL(非常便宜&#xff0c;几块钱)STM32F103C8T6(几块钱) 2.引脚连线 USB-TTLSTM32TXPA10RXPA9VCC3.3VGNDGND 注意事项&#xff1a; 跳线帽位置&#xff1a;BOOT0接高电平(1)&#xff0c;BOOT1接低电平(0)每次上传程序前需要按一下复位键(之后&#xff0c;跳线帽…

2020年全国硕士研究生入学统一考试管理类专业学位联考逻辑试题——纯享题目版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;考取过HCIE Cloud Computing、CCIE Security、CISP等证书。&#x1f433; &#x1f495;兴趣爱好&#xff1a;b站天天刷&#xff0c;题目常常看&a…

Nginx SSL使用自制证书

1. 生成证书 keytool -genkey -v -alias <Alias别名> -keyalg RSA -keystore <KeyStore文件> -validity <有效期> keytool -genkey -v -alias nginx -keyalg RSA -keystore nginx.keystore -validity 36500 alias别名为 nginxkeystore文件为 nginx.keystore…

【Nginx】第七章 Nginx原理与优化参数配置

7.1 Nginx原理 master-workers的机制的好处 首先&#xff0c;对于每个worker进程来说&#xff0c;独立的进程&#xff0c;不需要加锁&#xff0c;所以省掉了锁带来的开销&#xff0c;同时在编程以及问题查找时&#xff0c;也会方便很多。 其次&#xff0c;采用独立的进程&…

第11节 跟上板块轮动的节奏

板块 文章目录 板块什么是板块板块的分类板块的轮动 板块相关接口本节课任务 什么是板块 股票板块是一些具有相同特征的股票的集合&#xff0c;命名通常也会简单明了的直接按照特征命名。例如沪深300板块&#xff0c;蓝筹板块。对上市公司进行“分班”不论是对于企业还是对于投…

Restful风格笔记

Restful风格知识点 RestController注解 在类上添加RestController可以默认类中的所有方法都带有ResponseBody注解&#xff0c;可以省去一个个添加的麻烦。 RestController RequestMapping("/restful") //CrossOrigin(origins {"http://localhost:8080"…

Linux系统Centos7 安装MySQL8.0详细步骤

MySql安装 1.下载wget命令 yum -y install wget 2. 在线下载mysql安装包 wget https://repo.mysql.com//mysql80-community-release-el7-3.noarch.rpm 3.MySQL的GPG升级了&#xff0c;需要更新&#xff0c;如果是新安装的MySQL&#xff0c;执行以下脚本即可&#xff1…

Python MongoDB复习第一章

Python 可以在数据库应用程序中使用。 最受欢迎的 NoSQL 数据库之一是 MongoDB。 MongoDB MongoDB 将数据存储在类似 JSON 的文档中&#xff0c;这使得数据库非常灵活和可伸缩。 为了能够测试本教程中的代码示例&#xff0c;您需要访问 MongoDB 数据库。 您可以在 https:/…

Vue.js中的状态管理:理解和使用Vuex

目录 前言 Vue.js 样式绑定 Vue.js class class 属性绑定 实例 1 实例 2 实例 3 实例 4 数组语法 实例 5 实例 6 Vue.js style(内联样式) 实例 7 实例 8 实例 9 Vue.js 组件 全局组件 全局组件实例 局部组件 局部组件实例 Prop Prop 实例 动态 Prop Pro…

力扣 98. 验证二叉搜索树

题目来源&#xff1a;https://leetcode.cn/problems/validate-binary-search-tree/description/ C题解1&#xff1a;中序遍历&#xff0c;递归法。获取数组&#xff0c;如果是递增则返回true&#xff0c;否则返回false。 class Solution { public:void zhongxu(TreeNode* node…

vue+leaflet笔记之热力图

vueleaflet笔记之热力图 文章目录 vueleaflet笔记之热力图开发环境代码简介插件简介与安装使用简介 详细源码(Vue3) 本文介绍了Web端使用 Leaflet开发库展示热力图方法 (底图来源:天地图)&#xff0c;结合leaflet.heat插件可以很容易的做出热力图&#xff0c;通过调整其配置参…
最新文章