本地缓存的多种实现介绍(推荐使用Caffeine)

本地缓存是提升应用性能的关键,采用key-value结构并需考虑线程安全、对象上限、清除策略和过期时间。Caffeine是一个高效的本地缓存框架,支持异步操作和更优的剔除算法,是GuavaCache的升级选择。文章提供了一个基于Caffeine的本地缓存简单实现示例。
摘要由CSDN通过智能技术生成

一、什么是本地缓存

        所谓本地缓存,就是和应用服务器一起的缓存工具,将需要缓存的数据放到本地缓存中,可以大大的提升访问速度。

二、需要考虑的问题

   2.1 数据结构

       一般来讲,为了提升缓存的效率,通常采用key-value结构进行数据存储,也就是说,缓存中的数据保存和读取都需要有一个key,通过key来读取固定的缓存value。

   2.2 线程安全

        本地缓存一定要考虑线程安全的问题,因为大多数情况下本地缓存都是一个全局可访问的变量,那么就会有多个线程同时访问,所以线程安全问题也不容忽视。

   2.3 对象上限

        因为是本地缓存,而本地内存中的数据是要占用JVM的堆内存的,所以内存是有上限要求的,如果无限存储,最终一定会导致OMM问题。

   2.4 清楚策略

        为了避免OMM的问题,一般会考虑再缓存中增加清楚策略,通过一定的手段定期的清理掉一些数据,来保证内存占用不会过大,常见清除策略主要有LRU(最近最少使用)、FIFO(先进先出)、LFU(最近最不常使用)、SOFT(软引用)、WEAK(弱引用)等。

   2.5 过期时间

        有了清除策略并不能保证百分百的可以删除数据,极端情况会使得某些数据一直无法删除。这时候就需要有一种机制,能够保证某些K-V一定可以删除。通常采用的方案是给每一个缓存的key设置过期时间,当达到过期时间之后直接删除,采用清除+过期时间双重保证

三、实现方式

        考虑到以上问题后,就可以考虑如何具体实现一个本地缓存了。

        最简单的方式是通过HashMap来实现,它本身就是一种K-V结构,并且如果用ConcurrentHashMap的话,也能保证线程安全,不过需要自己实现对象上限、过期策略以及清除策略。

        除此之外,也有一些比较成熟的开源的本地缓存框架可以直接用,比较常用的有:

        Guava Cache、Caffeine(推荐)、Encache

        推荐优先使用Caffeine作为本地缓存,在功能上,GuavaCache支持的功能,Caffeine都支持,另外Caffeine支持异步Cache和写入外部资源,这两个GuavaCache是不支持的。Caffeine也是Spring 5默认支持的Cache,而且性能方面也要比GuavaCache好很多,主要有以下几个原因:

        1)剔除算法:GuavaCahe采用的是LRU算法,而Caffeine采用的是Window TinyLFU算法,这是两者之间最根本的区别。

        2)立即生效:Guava会把立即生效(例如:expireAfterAccess(0) and expireAfterWrite(0)转成设置最大Size为0。这就导致剔除提醒的原因是Size而不是Expired。Caffiene能正确识别这种原因。

        3)取代提醒:Guava只要数据被替换,不管什么原因,都会触发剔除监听器。而Caffiene在取代值和先前值得引用完全一样时不会触发监听器。

        4)异步:Caffiene的很多工作都是交给线程池去做的(默认:ForkJoinPool.commonPool())例如:剔除监听器、刷新机制、维护工作等。

四、基于Caffeine实现本地缓存

        4.1 导入依赖

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

        4.2 简单工具类

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.beans.factory.InitializingBean;

import java.util.concurrent.TimeUnit;

/**
 * 本地缓存工具
 * @date 2023/5/10 22:28
 */
@Component
public class LocalCacheManager implements InitializingBean {

    private Cache<String, String> localCache;

    /**
     * 向缓存中保存数据,如果已经存在则不覆盖
     * @param key
     * @param value
     */
    public void putIfNotExist(String key, String value) {
        if (localCache.getIfPresent(key) == null) {
            localCache.put(key, value);
        }
    }

    /**
     * 根据key获取缓存数据
     * @param key
     * @return
     */
    public String get(String key) {
        return localCache.getIfPresent(key);
    }

    /**
     * 删除缓存
     * @param key
     */
    public void del(String key) {
        localCache.invalidate(key);
    }

    /**
     * 在bean初始化时,初始化本地缓存
     */
    @Override
    public void afterPropertiesSet() {
        localCache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.SECONDS)
                .expireAfterAccess(10, TimeUnit.SECONDS)
                .maximumSize(1000)
                .build();
    }
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橡 皮 人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值