hutool工具实践-缓存

简介

依赖引入

java 复制代码
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-cache</artifactId>
            <version>5.8.17</version>
        </dependency>

hutool工具既可以像上一章hutool工具实践-验证码-CSDN博客所说直接全部引入,也可以分模块引入

使用示例

先进先出

java 复制代码
    /**
     * FIFO(first in first out) 先进先出策略。
     * 元素不停的加入缓存直到缓存满为止,当缓存满时,
     * 清理过期缓存对象,清理后依旧满则删除先入的缓存(链表首部对象)。
     *
     * 优点:简单快速 缺点:不灵活,不能保证最常用的对象总是被保留
     */
    @Test
    public void fifoCacheTest() {
        Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3);

        //加入元素,每个元素可以设置其过期时长,DateUnit.SECOND.getMillis()代表每秒对应的毫秒数,在此为3秒
        fifoCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
        fifoCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
        fifoCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);

        //由于缓存容量只有3,当加入第四个元素的时候,根据FIFO规则,最先放入的对象将被移除
        fifoCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);

        //value1为null
        String value1 = fifoCache.get("key1");

        System.out.println(value1);
    }

过期时间缓存

java 复制代码
 /**
     * 定时缓存,对被缓存的对象定义一个过期时间,当对象超过过期时间会被清理。
     * 此缓存没有容量限制,对象只有在过期后才会被移除。
     *
     * @throws InterruptedException
     */
    @Test
    public void timeCacheTest() throws InterruptedException {
        TimedCache<Object, Object> timeCache = CacheUtil.newTimedCache(1000);
        timeCache.put("userName","张三", DateUnit.MINUTE.getMillis());

        TimeUnit.SECONDS.sleep(1);
        Object userName = timeCache.get("userName");

        System.out.println(userName);
    }

如果用户在超时前调用了get(key)方法,会重头计算起始时间。举个例子,用户设置key1的超时时间5s,用户在4s的时候调用了get("key1"),此时超时时间重新计算,再过4s调用get("key1")方法值依旧存在。如果想避开这个机制,请调用get("key1", false)方法。

**此缓存没有容量限制,对象只有在过期后才会被移除,如果启动了定时器(**schedulePrune方法),那会定时清理缓存中的过期值,但是如果不起动,那只有在get这个值得时候才检查过期并清理。不启动定时器带来的问题是:有些值如果长时间不访问,会占用缓存的空间

最近最久未使用缓存

java 复制代码
    /**
     * LRU (least recently used)最近最久未使用缓存。
     * 根据使用时间来判定对象是否被持续缓存,当对象被访问时放入缓存,当缓存满了,
     * 最久未被使用的对象将被移除。此缓存基于LinkedHashMap,因此当被缓存的对象每被访问一次,
     * 这个对象的key就到链表头部。这个算法简单并且非常快,他比FIFO有一个显著优势是经常使用的对象不太可能被移除缓存。
     * 缺点是当缓存满时,不能被很快的访问。
     */
    @Test
    public void lruCacheTest() {
        Cache<String, String> lruCache = CacheUtil.newLRUCache(3);
        //通过实例化对象创建
        //LRUCache<String, String> lruCache = new LRUCache<String, String>(3);
        lruCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
        lruCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
        lruCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
        lruCache.get("key1");//使用时间推近
        lruCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);

        //由于缓存容量只有3,当加入第四个元素的时候,根据LRU规则,最少使用的将被移除(2被移除)
        String value2 = lruCache.get("key"); //null
    }

最少使用率策略

java 复制代码
    /**
     * LFU(least frequently used) 最少使用率策略。
     * 根据使用次数来判定对象是否被持续缓存(使用率是通过访问次数计算),
     * 当缓存满时清理过期对象,清理后依旧满的情况下清除最少访问(访问计数最小)的对象并将其他对象的访问数减去这个最小访问数,
     * 以便新对象进入后可以公平计数。
     */
    @Test
    public void lfuCacheTest() {
        Cache<String, String> lfuCache = CacheUtil.newLFUCache(3);
        //通过实例化对象创建
        //LFUCache<String, String> lfuCache = new LFUCache<String, String>(3);

        lfuCache.put("key1", "value1", DateUnit.SECOND.getMillis() * 3);
        lfuCache.get("key1");//使用次数+1
        lfuCache.put("key2", "value2", DateUnit.SECOND.getMillis() * 3);
        lfuCache.put("key3", "value3", DateUnit.SECOND.getMillis() * 3);
        lfuCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);

        //由于缓存容量只有3,当加入第四个元素的时候,根据LFU规则,最少使用的将被移除(2,3被移除)
        String value2 = lfuCache.get("key2");//null
        String value3 = lfuCache.get("key3");//null
    }

说明

hutool的缓存策略均是基于缓存实现的,单独使用的机会较少(比较适合一些较为简单的单体项目),使用场景较多的情况是:结合redis等缓存技术做的多级缓存,提升系统性能

源码浅析

整个cache模块的核心接口在cn.hutool.cache.Cache,定义了缓存的相关方法

cache的模板实现是AbstractCache,在该抽象模板中实现了大部分方法,定义了最关键的方法:

复制代码
putWithoutLock

其中pruneCache清理缓存的方法由后续子类根据各自的特征实现
getWithoutLock

实践案例

待补充

相关推荐
曹牧3 分钟前
Spring:@RequestMapping注解,匹配的顺序与上下文无关
java·后端·spring
daixin88486 分钟前
cursor无法正常使用gpt5.5等模型解决方案
java·redis·cursor
韦禾水1 小时前
记录一次项目部署到tomcat的异常
java·tomcat
曦月合一1 小时前
树莓派安装jdk、tomcat、vnc、谷歌浏览器开机自启等环境配置
java·tomcat·树莓派
excel1 小时前
如何解决 Nuxt DevTools 中关于 unstorage 包的报错
前端
Rust研习社2 小时前
使用 Axum 构建高性能异步 Web 服务
开发语言·前端·网络·后端·http·rust
此剑之势丶愈斩愈烈2 小时前
openssl 自建证书
java
面汤放盐2 小时前
何时使用以及何时不应使用微服务:没有银弹
java·运维·云计算
0xDevNull2 小时前
Spring Boot 自动装配:从原理到实践
java·spring boot·后端
C澒2 小时前
AI 生码 - API2Code:接口智能匹配与 API 自动化生码全链路设计
前端·低代码·ai编程