网站首页 > java教程 正文
通常情况下,为了提升服务性能,使用缓存框架是一个非常常见的选择。在Java语境下,经过我查阅,Caffeine被称作地标最强Java本地缓存框架。Caffeine是站在巨人(Guava Cache)的肩膀上,优化了算法发展而来。
在之前的性能测试框架开发中,通常用的缓存的时候都直接用java.util.concurrent.ConcurrentHashMap,但一涉及到过期策略就有点难以为继,搞不定了。经过简单学习实践,也算是Caffeine入门了。下面分享一下学习成果。
简介
Caffeine是Java语言的本地缓存性能框架,兼容Groovy语言,其他各位可以自行搜索。
常用功能
我主要用到Caffeine功能3点:
- 灵活的过期策略,可以访问计时过期、写入计时过期、自定义
- 灵活的写入策略,可以手动,还能同步,还可以异步
- API简单,上手快
其他高级功能暂时用不到,Caffeine性能数据,下次我单独JMH测试一下。
功能演示
主要实践3中写入策略的实践,过期策略其实只用前两种(访问、写入)即可满足现在的需求。
手动写入
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))
}
}
控制台打印:
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
同步写入
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)
}
}
控制台打印:
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即可。
异步加载
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))
}
}
控制台打印:
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个信息:
- 加载程序是在CompletableFuture执行get之前完成的。
- 缓存过期之后,CompletableFuture还是可以获取值的。但是asyncCache.getIfPresent(1)返回值就是null了。
关于Caffeine功能的实践就到这里了,基本上就是半小时之内上手。这里友情提醒一下,Caffeine最新版本不支持JDK8了,目前我使用JDK8的Caffeine版本信息如下:
compile group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: '2.9.3'
猜你喜欢
- 2024-10-25 Redis学习3——Redis应用之缓存(redis的缓存的使用方式)
- 2024-10-25 Java高级——缓存的使用场景(java缓存机制)
- 2024-10-25 java中常用的几种缓存类型介绍(java常用缓存技术)
- 2024-10-25 本地缓存之王caffeine#代码(本地缓存 js)
- 2024-10-25 skywalking agent 本地缓存队列参数设置
- 2024-10-25 史上最实用的:分布式缓存方案(分布式缓存设计方案)
- 2024-10-25 使用Guava作为本地缓存让系统飞起来
- 2024-10-25 深究分布式缓存的九个点(分布式缓存技术有哪些)
- 2024-10-25 面试题之java缓存总结,从单机缓存到分布式缓存架构
- 2024-10-25 JVM级别的本地缓存框架Guava Cache:探寻实现细节与核心机制
你 发表评论:
欢迎- 最近发表
-
- pyinstaller打包python程序高级技巧
- 将python打包成exe的方式(python打包成exe的方法)
- Python打包:如何将 Flask 项目打包成exe程序
- py2exe实现python文件打包为.exe可执行程序(上篇)
- 如何将 Python 项目打包成 exe,另带卸载功能!
- Python打包成 exe,太大了该怎么解决?
- 可视化 Python 打包 exe,这个神器绝了!
- 案例详解pyinstaller将python程序打包为可执行文件exe
- Cocos 3.x 菜鸟一起玩:打包window程序
- 怎么把 Python + Flet 开发的程序,打包为 exe ?这个方法很简单!
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)