当前位置:

首页 > 编程开发 > Java怎么设置过期时间的map

Java怎么设置过期时间的map

一、技术背景在实际的项目开发中,我们经常会使用到缓存中间件(如redis、MemCache等)来帮助我们提高系统的可用性和健壮性。但是很多时候如果项目比较简单,就没有必要为了使用缓存而专门引入Redis等等中间件来加重系统的复杂性。那么Java本身有没有好用的轻量级的缓存组件呢。答案当然是有喽,而且方法不止一种。常见的解决方法有:ExpiringMap、LoadingCache及基于HashMap的封装三种。二、技术效果实现缓存的常见功能,如过时删除策略热点数据预热三、ExpiringMap3.1功能简介

本文目录

    一、技术背景

    在实际的项目开发中,我们经常会使用到缓存中间件(如redis、MemCache等)来帮助我们提高系统的可用性和健壮性。

    但是很多时候如果项目比较简单,就没有必要为了使用缓存而专门引入Redis等等中间件来加重系统的复杂性。那么Java本身有没有好用的轻量级的缓存组件呢。

    答案当然是有喽,而且方法不止一种。常见的解决方法有:ExpiringMap、LoadingCache及基于HashMap的封装三种。

    二、技术效果

    • 实现缓存的常见功能,如过时删除策略

    • 热点数据预热

    三、ExpiringMap

    3.1 功能简介

    • 可设置Map中的Entry在一段时间后自动过期。

    • 可设置Map最大容纳值,当到达Maximum size后,再次插入值会导致Map中的第一个值过期。

    • 可添加监听事件,在监听到Entry过期时调度监听函数。

    • 可以设置懒加载,在调用get()方法时创建对象。

    3.2 源码

    github地址

    3.3 示例

    添加依赖(Maven)

     
        net.jodah 
        expiringmap 
        0.5.8 
    

    示例源码

    public class ExpiringMapApp {
    
        public static void main(String[] args) {
            // maxSize: 设置最大值,添加第11个entry时,会导致第1个立马过期(即使没到过期时间)
            // expiration:设置每个key有效时间10s, 如果key不设置过期时间,key永久有效。
            // variableExpiration: 允许更新过期时间值,如果不设置variableExpiration,不允许后面更改过期时间,一旦执行更改过期时间操作会抛异常UnsupportedOperationException
            // policy:
            //        CREATED: 只在put和replace方法清零过期时间
            //        ACCESSED: 在CREATED策略基础上增加, 在还没过期时get方法清零过期时间。
            //        清零过期时间也就是重置过期时间,重新计算过期时间.
            ExpiringMap map = ExpiringMap.builder()
                .maxSize(10)
                .expiration(10, TimeUnit.SECONDS)
                .variableExpiration().expirationPolicy(ExpirationPolicy.CREATED).build();
    
            map.put("token", "lkj2412lj1412412nmlkjl2n34l23n4");
            map.put("name", "管理员", 20000, TimeUnit.SECONDS);
    
            // 模拟线程等待...
            try {
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("token ===> " + map.get("token"));
            System.out.println("name ===> " + map.get("name"));
    
            // 注意: 在创建map时,指定的那些参数如过期时间和过期策略都是全局的, 对map中添加的每一个entry都适用.
            //        在put一个entry键值对时可以对当前entry 单独设置 过期时间、过期策略,只对当前这个entry有效.
        }
    }

    运行结果

    token ===> null
    name ===> 管理员

    注意
    在创建map时,指定的那些参数如过期时间和过期策略都是全局的, 对map中添加的每一个entry都适用。
    在put一个entry键值对时可以对当前entry 单独设置 过期时间、过期策略,只对当前这个entry有效.

    四、LoadingCache

    4.1 功能简介

    Google开源出来的一个线程安全的本地缓存解决方案。

    特点:提供缓存回收机制,监控缓存加载/命中情况,灵活强大的功能,简单易上手的api。

    4.2 示例

    源码

    public class LoadingCacheApp {
    
        public static void main(String[] args) throws Exception {
            // maximumSize: 缓存池大小,在缓存项接近该大小时, Guava开始回收旧的缓存项
            // expireAfterAccess: 设置时间对象没有被读/写访问则对象从内存中删除(在另外的线程里面不定期维护)
            // removalListener: 移除监听器,缓存项被移除时会触发的钩子
            // recordStats: 开启Guava Cache的统计功能
            LoadingCache cache = CacheBuilder.newBuilder()
                .maximumSize(100)
                .expireAfterAccess(10, TimeUnit.SECONDS)
                .removalListener(new RemovalListener() {
                    @Override
                    public void onRemoval(RemovalNotification removalNotification) {
                        System.out.println("过时删除的钩子触发了... key ===> " + removalNotification.getKey());
                    }
                })
                .recordStats()
                .build(new CacheLoader() {
                    // 处理缓存键不存在缓存值时的处理逻辑
                    @Override
                    public String load(String key) throws Exception {
                        return "不存在的key";
                    }
                });
    
            cache.put("name", "小明");
            cache.put("pwd", "112345");
    
            // 模拟线程等待...
            try {
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("token ===> " + cache.get("name"));
            System.out.println("name ===> " + cache.get("pwd"));
        }
    }

    运行结果

    过时删除的钩子触发了... key ===> name
    token ===> 不存在的key
    过时删除的钩子触发了... key ===> pwd
    name ===> 不存在的key

    4.3 移除机制

    guava做cache时候数据的移除分为被动移除和主动移除两种。

    被动移除

    • 基于大小的移除:数量达到指定大小,会把不常用的键值移除

    • 基于时间的移除:expireAfterAccess(long, TimeUnit) 根据某个键值对最后一次访问之后多少时间后移除。expireAfterWrite(long, TimeUnit) 根据某个键值对被创建或值被替换后多少时间移除

    • 基于引用的移除:主要是基于java的垃圾回收机制,根据键或者值的引用关系决定移除

    主动移除

    • 单独移除:Cache.invalidate(key)

    • 批量移除:Cache.invalidateAll(keys)

    • 移除所有:Cache.invalidateAll()

    如果配置了移除监听器RemovalListener,则在所有移除的动作时会同步执行该listener下的逻辑。

    如需改成异步,使用:RemovalListeners.asynchronous(RemovalListener, Executor).

    4.4 其他

    • 在put操作之前,如果已经有该键值,会先触发removalListener移除监听器,再添加

    • 配置了expireAfterAccess和expireAfterWrite,但在指定时间后没有被移除。

    • 删除策略逻辑:

    CacheBuilder构建的缓存不会在特定时间自动执行清理和回收工作,也不会在某个缓存项过期后马上清理,它不会启动一个线程来进行缓存维护,因为首先线程相对较重,其次某些环境限制线程的创建。

    它会在写操作时顺带做少量的维护工作,或者偶尔在读操作时做。当然,也可以创建自己的维护线程,以固定的时间间隔调用Cache.cleanUp()。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    Java单元测试入门:使用JUnit 5编写第一个测试用例
    Java单元测试入门:使用JUnit 5编写第一个测试用例

    面向初学者的JUnit 5实用入门指南。从测试概念、Maven依赖配置,到手把手编写首个单元测试用例及断言验证,助你掌握Java单元测试的核心流程。

    Java变量未初始化报错解析:局部变量与成员变量默认值差异
    Java变量未初始化报错解析:局部变量与成员变量默认值差异

    深入解析Java中局部变量未初始化编译报错与成员变量自动赋予默认值的机制差异,涵盖JVM内存分配、编译期确定性赋值检查与实际排查修复方案。

    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat
    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat

    详细讲解在Java中获取当前系统时间并进行格式化输出的两种核心方案:基于Java 8全新日期时间API的DateTimeFormatter与传统遗留的SimpleDateFormat,包含完整代码示例、线程安全机制对比及生产选型建议。

    Java中final与static final常量的定义及初始化规则
    Java中final与static final常量的定义及初始化规则

    深入解析Java中final变量与static final常量的定义、内存语义、初始化时机及合法赋值路径,涵盖编译期常量优化与实战避坑指南。

    Java抽象方法与接口方法的区别及选型建议
    Java抽象方法与接口方法的区别及选型建议

    深入对比Java中抽象类抽象方法与接口方法的语法演进、设计意图及运行期差异,并提供清晰的架构选型决策流程与实战范例。

    Java实现HTTP请求与JSON解析的完整代码示例
    Java实现HTTP请求与JSON解析的完整代码示例

    本文提供Java标准库HttpClient发起HTTP GET/POST请求并结合Jackson进行JSON数据反序列化与序列化的完整代码示例与工程实践指南。

    Java递归出现StackOverflowError的原因分析及栈空间优化方案
    Java递归出现StackOverflowError的原因分析及栈空间优化方案

    详细分析Java递归调用出现StackOverflowError的原因,结合代码说明线程栈、栈帧和递归深度之间的关系,并介绍终止条件排查、迭代改写、减少栈帧开销以及通过-Xss调整JVM栈空间的方法。

    Java空指针异常(NPE)的代码排查与修复实例
    Java空指针异常(NPE)的代码排查与修复实例

    针对Java中常见的NullPointerException(NPE),本文从堆栈日志定位、典型代码触发场景、具体修复代码对比到防御体系进行系统讲解,提供实用且易上手的排查与修复方案。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。