首页 > 编程语言 >快速上手 Caffeine:Java 缓存库初学者指南

快速上手 Caffeine:Java 缓存库初学者指南

时间:2024-07-16 20:26:24浏览次数:11  
标签:cache Java key1 Cache Caffeine 条目 缓存

一、背景

  1. 简介: Caffeine 是一个高性能的 Java 缓存库,旨在为现代应用程序提供快速、高效的缓存解决方案。它由 Google Guava Cache 的创始人之一开发,具备基于时间的过期、基于大小的回收、异步加载、统计信息等多种特性。Caffeine的性能有多么强大呢?以下是官方给出的基准测试图(在该基准测试中,8 个线程同时从配置了最大容量的高速缓存中读取数据。)

在这里插入图片描述

  1. 应用场景

    • Web 应用的会话管理:缓存用户会话信息,以减少数据库查询次数。

    • 配置和数据的本地缓存:缓存配置文件或常用数据,以减少对外部系统的访问延迟。

    • 计算结果缓存:缓存频繁计算的结果,如搜索结果、数据分析结果等,以提高响应速度。

    • 分布式系统中的中间缓存层:在分布式系统中使用本地缓存,减轻数据库或其他后端服务的负载。

  2. 示例代码

    • 导入依赖:
    <dependency>
        <groupId>com.github.ben-manes.caffeine</groupId>
        <artifactId>caffeine</artifactId>
    </dependency>
    
    • 测试代码:
    import com.github.benmanes.caffeine.cache.Cache;
    import com.github.benmanes.caffeine.cache.Caffeine;
    
    import java.util.concurrent.TimeUnit;
    
    public class CaffeineExample {
    
        public static void main(String[] args) {
            // 创建一个Caffeine缓存
            Cache<String, String> cache = Caffeine.newBuilder()
                    .maximumSize(100) // 设置缓存的最大条目数
                    .expireAfterWrite(10, TimeUnit.MINUTES) // 设置写入后10分钟过期
                    .build();
    
            // 放入一个条目
            cache.put("key1", "value1");
    
            // 获取一个条目
            String value = cache.getIfPresent("key1");
            System.out.println("key1: " + value);
    
            // 使用计算函数获取一个条目(如果不存在,则计算并放入缓存)
            value = cache.get("key2", k -> "computedValue");
            System.out.println("key2: " + value);
    
            // 删除一个条目
            cache.invalidate("key1");
        }
    }
    
    

二 、Caffeine 常见缓存淘汰策略

缓存淘汰策略用于在缓存空间有限时,确保频繁访问和最近使用的条目得以保留,同时移除不常用的条目,从而优化内存使用和缓存命中率。

  1. 基于容量的清理
    • Caffeine 允许配置缓存的最大容量,当缓存容量达到上限时,Caffeine 会根据其内部的策略自动清理一些缓存项。
    • 这种策略通常采用窗口TinyLFU算法(Least Frequently Used)来判断条目的使用频率。
// 创建一个最大容量为3的缓存
Cache<String, String> cache = Caffeine.newBuilder()
    .maximumSize(3)
    .build();
  1. 基于时间的清理
    1. TTL(Time to Live):在缓存项创建的时指定一段时间,到期进行自动清理。
    2. TTR(Time to Refresh):在缓存项最后一次访问一段时间后进行自动清理。
// 创建一个写入后2秒过期的缓存
Cache<String, String> cache = Caffeine.newBuilder()
    .expireAfterWrite(2, TimeUnit.SECONDS)
    .build();
// 创建一个访问后2秒过期的缓存
Cache<String, String> cache = Caffeine.newBuilder()
    .expireAfterAccess(2, TimeUnit.SECONDS)
    .build();
  1. 显式移除:可以通过API手动移除缓存中的条目。
// 创建一个缓存
Cache<String, String> cache = Caffeine.newBuilder()
    .maximumSize(100)
    .build();

// 放入一个条目
cache.put("key1", "value1");

// 缓存应该包含条目
System.out.println("Initial Cache: " + cache.getIfPresent("key1"));

// 显式移除条目
cache.invalidate("key1");

// 缓存应该不包含条目
System.out.println("After Removal: " + cache.getIfPresent("key1"));

三、常见API

  1. 创建缓存:

    • Caffeine.newBuilder(): 创建一个新的缓存构建器,可以设置各种缓存参数。
  2. 缓存配置:

    • maximumSize(long size): 设置缓存的最大容量,超过这个容量后会触发缓存回收。

    • expireAfterWrite(long duration, TimeUnit unit): 设置缓存项在写入后多长时间过期。

    • expireAfterAccess(long duration, TimeUnit unit): 设置缓存项在访问后多长时间过期。

  3. 缓存操作:

    • put(K key, V value): 将一个键值对放入缓存。

    • getIfPresent(Object key): 获取缓存中指定键的值,如果不存在则返回null

    • get(K key, Function<? super K, ? extends V> mappingFunction): 获取缓存中指定键的值,如果不存在则使用提供的映射函数计算值并放入缓存。

    • invalidate(Object key): 移除缓存中指定键的条目。

    • invalidateAll(Iterable<?> keys): 移除缓存中指定键集合的所有条目。

    • invalidateAll(): 移除缓存中的所有条目。

四、Redis 与 Caffeine

1. 适用 Caffeine 的场景

  1. 本地缓存需求:适合数据量小且仅需本地缓存的场景,如单节点应用或无需共享缓存的多节点应用。
  2. 高性能和低延迟要求:适用于需要极低访问延迟和高吞吐量的应用,因为Caffeine运行在本地内存中,访问速度快。
  3. 简化架构:无需引入额外组件,只需在应用中引入相应库即可,简化系统架构。
  4. 不需要持久化:适用于无需持久化的缓存数据,如缓存计算结果或短时间内频繁访问的数据。

2. 适用 Redis 的场景

  1. 分布式缓存需求:适合多个应用服务器共享缓存,作为独立的分布式缓存系统,支持多个客户端访问。
  2. 大数据量缓存:适用于缓存数据量超出单个服务器内存限制的场景,通过分布式特性将数据分布到多个节点。
  3. 持久化需求:需要持久化缓存数据以防数据丢失,提供数据持久化功能确保数据可靠性。
  4. 丰富的数据结构:支持多种数据结构,如字符串、哈希、列表、集合和有序集合,适用于复杂缓存场景。

3. 综合比较

  1. 访问速度:Caffeine 本地缓存访问速度更快,但 Redis 可通过分片和集群提高读写性能。
  2. 数据共享:Redis 适合需要多个应用实例共享数据的场景,而 Caffeine 仅适用于单实例缓存。
  3. 数据持久化:Redis 提供持久化机制,适合需要持久保存缓存数据的应用。Caffeine 不支持持久化。
  4. 运维复杂度:Caffeine 易于使用和集成,无需额外运维工作。Redis 需要独立部署和运维。

标签:cache,Java,key1,Cache,Caffeine,条目,缓存
From: https://blog.csdn.net/m0_64516972/article/details/140472846

相关文章

  • Java SE 总结
    目录1初始Java2数据类型与变量3运算符4程序逻辑控制5方法的使用6数组的定义与使用7 Java类和对象8继承和多态9抽象类和接口10Java中String类11Java异常1初始JavaJDK,JRE,JVMJava代码书写注释标识符关键字标识符:在程序中由用户给类名......
  • Java基础-学习笔记04
    04运算符进制1.运算符逻辑与&和短路与&&共同点:两个条件都为true时,结果为true,否则为false。&逻辑与:不管第一个条件是否为false,第二个条件都要判断;&&短路与:如果第一个条件判断为false,则第二个条件不会判断。逻辑或|和短路或||共同点:两个条件只要有一个成立,结果......
  • Java小常识
    publicstaticvoidmain(Stringarge[])ssaticpublicvoidmain(Stringargs[])都是有效的。Java的注解方式有///**  *//**/实例方法可以直接调用本类的类方法。面向对象程序的三个设计是封装,继承和多态Java语言的主要特点是简单,安全,面向对象,平台无关数组必须......
  • 暑假Java自学每日进度总结1
    今日所学:一.常用的cmd命令:1>盘符:2>dir(显示当前文件所有目录)3>cd目录(打开该目录)4>cd..(回到上一目录)5>cd(回到当前盘符初始态)6>cls(清屏)7>exit(退出cmd命令界面)8>cd目录1\目录2...(打开多级目录)二.创建用cmd打开软件的快捷方式:使用环境变量:1>电脑2>属性3>高......
  • JavaSE的整体总结
    JavaSE(JavaStandardEdition)是Java编程语言的基础,广泛应用于各种开发场景。本文将详细介绍JavaSE的基本概念和核心功能,包括初识Java、数据类型和变量、运算符、程序逻辑控制、方法的使用、数组的定义与使用、类和对象、继承和多态、抽象类和接口、String类以及异常处理。1.......
  • 揭秘 Java 变长参数:如何优雅地处理不定数量的字符串
    哈喽,大家好,我是木头左!理解变长参数:基础概念在Java中,变长参数也称为可变参数,它允许你传递任意数量的参数到一个方法中。这个特性是通过使用三个点符号...来实现的。当你在方法的参数列表中使用...时,任何传递给该方法的额外参数都会被当作数组来处理。这为提供了一种灵活的方式......
  • JAVA初级之IO流(其他流)
    目录1、缓冲流/处理流1.1概述1.2字节缓冲流1.2.1构造方法1.2.2 测试  1.3字符缓冲流1.3.1构造方法1.3.2特有方法1.3.3代码演示 2、转换流2.1因为什么而提出的转换流?2.2 InputStreamReader类2.3 OutputStreamWriter类2.4转换图解3、对象流/序列......
  • Java实现将json数据转换为sql insert语句
    Java实现将json数据转换为sqlinsert语句importcom.fasterxml.jackson.core.JsonProcessingException;importcom.fasterxml.jackson.databind.JsonNode;importcom.fasterxml.jackson.databind.ObjectMapper;importjava.util.Iterator;importjava.util.Map;publicclassJson......
  • Java基础之数据类型扩展
    一、整数扩展Java中四种进制的表示方式:二进制0b,八进制0,十进制默认,十六进制0x或0XpublicclassDemon02{publicstaticvoidmain(String[]args){//二进制inti=0b10;//八进制inti2=010;//默认十进制i......
  • CSS 不用JavaScript实现动画 box-shadow 渐变实现内切角
    阴影实现的关键点在于使用伪元素绝对定位在容器的一角,元素本身透明,阴影扩散开形成内切圆角效果阴影实现缺点,单个标签最多只能是2个内切圆角径向渐变实现内切圆角可以是4边HTML:<divclass="shadow">使用阴影的扩散半径实现内切圆角</div><divclass="shadow2">阴影实现缺点......