前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Caffeine高性能本地缓存框架初探

Caffeine高性能本地缓存框架初探

作者头像
FunTester
发布于 2023-08-04 04:01:48
发布于 2023-08-04 04:01:48
35700
代码可运行
举报
文章被收录于专栏:FunTesterFunTester
运行总次数:0
代码可运行

通常情况下,为了提升服务性能,使用缓存框架是一个非常常见的选择。在Java语境下,经过我查阅,Caffeine被称作地表最强Java本地缓存框架。Caffeine是站在巨人(Guava Cache)的肩膀上,优化了算法发展而来。

在之前的性能测试框架开发中,通常用的缓存的时候都直接用java.util.concurrent.ConcurrentHashMap,但一涉及到过期策略就有点难以为继,搞不定了。经过简单学习实践,也算是Caffeine入门了。下面分享一下学习成果。

简介

Caffeine是Java语言的本地缓存性能框架,兼容Groovy语言,其他各位可以自行搜索。

常用功能

我主要用到Caffeine功能3点:

  1. 灵活的过期策略,可以访问计时过期、写入计时过期、自定义
  2. 灵活的写入策略,可以手动,还能同步,还可以异步
  3. API简单,上手快

其他高级功能暂时用不到,Caffeine性能数据,下次我单独JMH测试一下。

功能演示

主要实践3中写入策略的实践,过期策略其实只用前两种(访问、写入)即可满足现在的需求。

手动写入

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import com.funtester.frame.SourceCode
import com.github.benmanes.caffeine.cache.Cache
import com.github.benmanes.caffeine.cache.Caffeine
import groovy.util.logging.Log4j2

import java.util.concurrent.TimeUnit
import java.util.function.Function

@Log4j2
class CaffeineManual extends SourceCode {

    static void main(String[] args) {
        Cache<Integer, Integer> cache = Caffeine.newBuilder()
                .maximumSize(100)
                .expireAfterWrite(100, TimeUnit.MILLISECONDS)
                .recordStats()
                .build()

        int key = 1
        log.info("无缓存返回: {}", cache.getIfPresent(key))
        log.info("无缓存自定义返回: {}", cache.get(key, new Function<Integer, Integer>() {

            @Override
            Integer apply(Integer integer) {
                return 3
            }
        }))
        cache.put(key, 2)
        log.info("手动赋值后返回: {}", cache.getIfPresent(key))
        sleep(1.0)
        log.info("缓存过期返回: {}", cache.getIfPresent(key))
        cache.put(key, 2)
        cache.invalidate(key)
        log.info("手动删除后返回: {}", cache.getIfPresent(key))
    }
}

控制台打印:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
21:41:30.329 main 无缓存返回: null
21:41:30.337 main 无缓存自定义返回: 3
21:41:30.338 main 手动赋值后返回: 2
21:41:31.360 main 缓存过期返回: null
21:41:31.364 main 手动删除后返回: null

同步写入

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import com.funtester.frame.SourceCode
import com.github.benmanes.caffeine.cache.CacheLoader
import com.github.benmanes.caffeine.cache.Caffeine
import com.github.benmanes.caffeine.cache.LoadingCache
import groovy.util.logging.Log4j2

import java.util.concurrent.TimeUnit

@Log4j2
class CaffeineSync extends SourceCode {

    static int cacheInit(int key) {
        log.info("返回赋值: {}", key)
        return key * 100;
    }

    static void main(String[] args) {
        LoadingCache<Integer, Integer> cache = Caffeine.newBuilder()
                .expireAfterWrite(1, TimeUnit.MINUTES)
                .maximumSize(100)
                .build(new CacheLoader<Integer, Integer>() {

                    @Override
                    Integer load(Integer integer) throws Exception {
                        return cacheInit(integer)
                    }
                });

        Integer value = cache.get(1)
        log.info("无缓存返回: {}", value)
        log.info("自定义返回: {}", cache.get(2, {
            return 31
        }))
        log.info("获取返回结果: {}", value)
        Map<Integer, Integer> resMap = cache.getAll([1, 2, 3])
        log.info("批量返回: {}",resMap)
    }
}

控制台打印:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
21:54:54.900 main 返回赋值: 1
21:54:54.903 main 无缓存返回: 100
21:54:54.963 main 自定义返回: 31
21:54:54.963 main 获取返回结果: 100
21:54:54.964 main 返回赋值: 3
21:54:54.965 main 批量返回: {1=100, 2=31, 3=300}

这里可以看到,自定义返回时,自定义的数值是优先于CacheLoader中的加载方法的。经过我测试,当自定义闭包里面如果报错的话,当前线程会中断。这时候可以用try-catch语法返回一个null即可。

异步加载

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

import com.funtester.frame.SourceCode
import com.funtester.frame.execute.ThreadPoolUtil
import com.github.benmanes.caffeine.cache.AsyncCache
import com.github.benmanes.caffeine.cache.Caffeine
import groovy.util.logging.Log4j2

import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit
import java.util.function.Function

@Log4j2
class CaffeineAsync extends SourceCode {

    static int cacheInit(int key) {
        return key * 100
    }

    static void main(String[] args) {
        AsyncCache<Integer, Integer> asyncCache = Caffeine.newBuilder()
                .expireAfterWrite(1, TimeUnit.SECONDS)
                .maximumSize(100).executor(ThreadPoolUtil.getFunPool()).buildAsync()
        CompletableFuture<Integer> future = asyncCache.get(1, new Function<Integer, Integer>() {

            @Override
            Integer apply(Integer integer) {
                log.info("开始加载缓存")
                sleep(1.0)
                return cacheInit(integer)
            }
        })
        log.info("FunTester1")
        sleep(2.0)
        log.info("FunTester2")
        log.info("异步加载返回: {}", future.get())
        sleep(2.0)
        log.info("缓存过期后Future返回: {}", future.get())
        log.info("缓存过期后cache返回: {}", asyncCache.getIfPresent(1))
        log.info("无缓存返回: {}", asyncCache.getIfPresent(2))
    }
}

控制台打印:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
22:13:06.728 main FunTester1
22:13:06.728 F-1  开始加载缓存
22:13:08.738 main FunTester2
22:13:08.747 main 异步加载返回: 100
22:13:10.748 main 缓存过期后Future返回: 100
22:13:10.749 main 缓存过期后cache返回: null
22:13:10.750 main 无缓存返回: null

这里我们看2个信息:

  1. 加载程序是在CompletableFuture执行get之前完成的。
  2. 缓存过期之后,CompletableFuture还是可以获取值的。但是asyncCache.getIfPresent(1)返回值就是null了。

关于Caffeine功能的实践就到这里了,基本上就是半小时之内上手。这里友情提醒一下,Caffeine最新版本不支持JDK8了,目前我使用JDK8的Caffeine版本信息如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    compile group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: '2.9.3'

FunTester原创专题推荐~

-- By FunTester

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-03-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Qt之Qfile类
很多应用程序都具备操作文件的能力,包括对文件进行写入和读取,创建和删除文件等等,甚至某些应用程序的就是为了操作文件,像WPS Office。基于此Qt框架中专门提供了对文件操作的类:QFile。
破晓的历程
2025/05/15
1090
Qt之Qfile类
QString与char *的相互转换
在进行编程时,我们经常需要用到字符串这种类型,毫无疑问,Qt 库中也对字符串类型进行了封装,QString 类提供了你能想到的所有字符串操作方法,给开发者带来了极大方便。
全栈程序员站长
2022/08/26
3.4K0
QT应用编程: 开发串口调试助手
串口调试助手,在嵌入式开发中是很常用的。比如: 通过串口打印测试数据、调试串口WIFI(ESP8266、有人WIFI..)、调试GSM模块、GPS模块、字库更新等等。
DS小龙哥
2022/01/07
4.2K0
QT应用编程: 开发串口调试助手
Qt 教程二
因为Qt是一个C++框架, 因此C++中所有的语法和数据类型在Qt中都是被支持的, 但是Qt中也定义了一些属于自己的数据类型, 下边给大家介绍一下这些基础的数类型。
用户11332765
2024/10/28
4620
[QT]QByteArray与char、int、float(及其数组)、string之间的互相转化
要用SQLite数据库去保存一段定长的char型数组,里面可能有\0等字符,所以当作字符串varchar处理铁定丢失数据,所以要用二进制保存BLOB,这样对应的QT数据类型要用QByteArray进行处理,原来只用到QByteArray转换成 char* 类型,其它的转换还没搞过,一弄发现还是有些门道,为了以后不再继续造轮子,就先写出来,标记一下。
zls365
2020/10/30
2.3K0
14.QT-QFile文件,QBuffer缓冲区,QDir目录,QFileSystemWatcher文件系统监视
QFile Qt中所有与IO相关的类都继承于QIODevice,继承图如下所示: 其中QFile类便是用于文件操作的类 在QT中,将文件当做一种特殊的外部设备对待(比如:串口,usb等就是外部设备)
诺谦
2018/05/28
2.4K0
Qt学习之路_6(Qt局域网聊天软件)
http://www.cnblogs.com/tornadomeet/archive/2012/07/04/2576355.html
bear_fish
2018/09/20
3.4K0
Qt学习之路_6(Qt局域网聊天软件)
【QT】QT容器
隐式数据共享类当作为函数参数传递的时候,不仅安全而且效率很高,因为传递的时候只是传递了数据的指针,数据本身只当自己被修改的时候才会去复制。简称写时复制。
半生瓜的blog
2023/05/13
3.6K0
【QT】QT容器
QT 关于int、double、string、QString格式相互转换的方法
QT 关于int、double、string、QString格式相互转换的方法 最近在QT中用到了很多数据格式转换的命令,稍作整理。 1,int与double //int转double int a = 1234; double b; b = a;//直接赋值就可以 //double转int double c = 123.456; int d; d = c;//d的结果为123,即只取整数部份 d = c*1000;//乘1000将小数消掉即可,注意int位数要求,避免溢出 2,int与string //i
acoolgiser
2019/08/14
20.4K0
QT应用编程: 基于UDP协议设计的大文件传输软件
功能介绍: 软件由客户端和服务器组成,客户端通过 UDP协议不断循环地向服务端发送文件,文件传输速率可以达到10MB/s以上,文件传输后支持自动删除,客户端上可以支持每分钟创建一个文件并以时间戳命名,每个生成的文件可以设置大小,默认大小为6GB; 服务端收到文件之后,将文件进行存储到本地,可以指定时间自动删除文件; 服务端可以动态计算传输速率,并写入日志文件; 服务器可以支持同时接收多个客户端的文件上传。
DS小龙哥
2022/01/07
2.9K0
QT应用编程: 基于UDP协议设计的大文件传输软件
02 qt基本控件及信号和槽
将string -----> QString [static] QString QString::fromStdString(const std::string &str) – 静态成员函数,可以直接使用类名调用 比如:
天天Lotay
2023/10/15
3580
02 qt基本控件及信号和槽
C++ Qt开发:字符串QString容器
在Qt框架中,QString 是一个强大而灵活的字符串容器,专为处理 Unicode 字符而设计。它提供了许多方便的方法来操作和处理字符串,使得在跨平台开发中能够轻松地进行文本操作。QString 是 Qt 开发中不可或缺的一部分,它的灵活性和强大的功能使其成为处理文本和字符串操作的理想选择。本篇博客将深入探讨 QString 的各种用法,包括字符串的连接、追加与移除、格式化输出、统计字符串长度、去空格操作、字符串的切割与截取,以及类型转换等,以帮助读者更好地利用这一重要的字符串容器。
王 瑞
2023/12/10
4460
C++ Qt开发:字符串QString容器
QString和QDateTime之间的相互转换
QDateTime是Qt中常用的日期时间类,我们经常会将其转换为QString类型,或者进行相反转换,具体方法如下。
用户7108768
2021/10/29
2.3K0
QT应用编程: 基于Qt设计的跨平台录音机功能
QT通过QAudioInput类读取声卡PCM数据,在封装WAV头,转为WAV格式的文件保存到本地。
DS小龙哥
2022/01/07
1.5K0
QT应用编程: 基于Qt设计的跨平台录音机功能
QT应用编程: 基于FFMPEG设计的精简版视频播放器
win32下使用FFMPEG 4.2.2库下载地址:https://download.csdn.net/download/xiaolong1126626497/12321684
DS小龙哥
2022/01/07
8430
QT应用编程: 基于FFMPEG设计的精简版视频播放器
FFMPEG音频视频开发:QT获取Android、Linux、Windows系统上的摄像头数据帧与声卡音频通过FFMPEG编码为MP4存储(v1.0)
声卡: win10 电脑自带声卡、罗技USB摄像头声卡、Android手机自带声卡都可以获取声音数据 摄像头: 手机摄像头、罗技USB摄像头
DS小龙哥
2022/01/12
1.8K0
FFMPEG音频视频开发:QT获取Android、Linux、Windows系统上的摄像头数据帧与声卡音频通过FFMPEG编码为MP4存储(v1.0)
C语言 整数与字符串的相互转换
C语言中整数与字符串的相互转换,有广泛应用的拓展函数(非标准库),也可以自己尝试简单的实现。
全栈程序员站长
2022/09/06
4K0
C语言 整数与字符串的相互转换
QT(二).计算器(4)
void QTextCodec::setCodecForTr ( QTextCodec * c ) [static]
franket
2021/09/14
6010
Qt开源作品35-秘钥生成器
在很多商业软件中,需要提供一些可以试运行的版本,这样就需要配套密钥机制来控制,纵观大部分的试用版软件,基本上采用以下几种机制来控制。
feiyangqingyun
2020/08/02
1.2K0
Qt开源作品35-秘钥生成器
C/C++ Qt 基础通用组件的应用
QT 是一个跨平台C++图形界面开发库,利用QT可以快速开发跨平台窗体应用程序,在QT中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率。
王 瑞
2022/12/23
3.9K0
C/C++ Qt 基础通用组件的应用
推荐阅读
相关推荐
Qt之Qfile类
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档