Java如何设置Map过期时间的的几种方法

news2024/11/16 13:45:21

一、技术背景

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

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

二、技术效果

  1. 实现缓存的常见功能
  2. 热点数据预热
  3. 简单限流
  4. 去重

三、ExpiringMap

3.1 ExpiringMap简介

ExpiringMap具有高性能、低开销、零依赖、线程安全、使用 ConcurrentMap 的实现过期 entries 等优点。
功能包括不限于:

  1. 设置 Map 中的 Entry 在一段时间后自动过期。
  2. 设置 Map 最大容纳值,当到达 Max size 后,再次插入值会导致 Map 中的第一个值过期。
  3. 设置 添加监听事件,在监听到 Entry 过期时调度监听函数。
  4. 设置懒加载,在调用 get() 方法时创建对象。
  5. 允许您了解条目预计何时过期

3.2 ExpiringMap使用

3.2.1 pom.xml 中添加依赖
        <!-- https://mvnrepository.com/artifact/net.jodah/expiringmap -->
        <dependency>
            <groupId>net.jodah</groupId>
            <artifactId>expiringmap</artifactId>
            <version>0.5.10</version>
        </dependency>
3.2.2 代码中使用
    /**
     * ① maxSize:Map存储的最大值,类似队列,容量固定,当操作map容量超出限制时,最开始的元素就会依次过期,只保留最新的;
     * ② expiration:过期时间;
     * ③ expirationListener:过期监听,当条目过期时,将同步调用过期侦听器,并且在侦听器完成之前,
     *  将阻止对映射的写入操作。还可以在单独的线程池中配置和调用异步过期侦听器,而不会阻塞映射操作;
     * ④ expirationPolicy:过期策略,包括 ExpirationPolicy.ACCESSED 和 ExpirationPolicy.CREATED 两种;
     *      1)ExpirationPolicy.ACCESSED :每进行一次访问,过期时间就会自动清零,重新计算;
     *      2)ExpirationPolicy.CREATED:在过期时间内重新 put 值的话,过期时间会清理,重新计算;
     * ⑤ variableExpiration:可变过期,条目可以具有单独可变的到期时间和策略:
     */
    public static  ExpiringMap<String, String> map = ExpiringMap.builder()
            .maxSize(1000)
            .expiration(2, TimeUnit.HOURS)
            .variableExpiration()
            .expirationPolicy(ExpirationPolicy.ACCESSED)
            .expirationListener((key, value) -> {
                System.out.println("SseEmitter已过期,key:"+ key);
            })
            .build();
3.2.3 参数说明
 ① maxSize:Map存储的最大值,类似队列,容量固定,当操作map容量超出限制时,最开始的元素就会依次过期,只保留最新的;
 ② expiration:过期时间;
 ③ expirationListener:过期监听,当条目过期时,将同步调用过期侦听器,并且在侦听器完成之前,
  将阻止对映射的写入操作。还可以在单独的线程池中配置和调用异步过期侦听器,而不会阻塞映射操作;
 ④ expirationPolicy:过期策略,包括 ExpirationPolicy.ACCESSED 和 ExpirationPolicy.CREATED 两种;
           1)ExpirationPolicy.ACCESSED :每进行一次访问,过期时间就会自动清零,重新计算;
           2)ExpirationPolicy.CREATED:在过期时间内重新 put 值的话,过期时间会清理,重新计算;
 ⑤ variableExpiration:可变过期,条目可以具有单独可变的到期时间和策略;
3.2.4 其他使用方式
		//为单个条目指定到期策略:
        map.put("1", "张三", ExpirationPolicy.CREATED);
        map.put("2", "李四", ExpirationPolicy.ACCESSED);

        //variableExpiration 可变过期 条目可以具有单独可变的到期时间和策略:
        map.put("3", "王五", ExpirationPolicy.ACCESSED, 5, TimeUnit.MINUTES);

        //过期时间和策略也可以即时更改:
        map.setExpiration("1", 5, TimeUnit.MINUTES);
        map.setExpirationPolicy("1", ExpirationPolicy.ACCESSED);

        //动态添加和删除过期侦听器:
        ExpirationListener<String, String> connectionCloser = (key, value) -> System.out.println(key+":"+value);
        //添加侦听器
        map.addExpirationListener(connectionCloser);
        //移除侦听器
        map.removeExpirationListener(connectionCloser);

        //设置懒加载
//        Map<String, String> stringMap = ExpiringMap.builder()
//                .expiration(10, TimeUnit.MINUTES)
//                .entryLoader(address -> address)
//                .build();
//        // 通过 EntryLoader 将值加载到map中
//        String value = stringMap.get("1");
//        System.out.println("value值:"+value);

        //获取条目的到期时间:单位:毫秒
        long expiration = map.getExpectedExpiration("1");
        System.out.println("距离过期时间还有:"+expiration+"毫秒");

        //重置条目的内部到期计时器:
        map.resetExpiration("1");

        //查看设置的过期时间
        map.getExpiration("1");
        System.out.println("设置的过期时间:"+map.getExpiration("1"));
        

测试结果

距离过期时间还有:299999毫秒
设置的过期时间:300000

四、Guava的LoadingCache

4.1 LoadingCache简介

做java的我们都知道Guava是一个编程工具类库,其中包含了很多高质量高性能的工具类和方法。其中,LoadingCache便是一个特别好用的功能,其背后的架构其实就是Guava cache,Guava Cache 是一个全内存的本地缓存实现,它提供了线程安全的实现机制,它可以加载缓存中不存在的数据,本质其实是一个键值对(key-value)的缓存,可以通过key获取到对应的缓存值value。
特点:提供缓存回收机制,监控缓存加载/命中情况,灵活强大的功能,简单易上手的api。

4.2 LoadingCache使用

4.2.1 pom.xml 中添加依赖
<dependency>
	<groupId>com.google.guava</groupId>
	<artifactId>guava</artifactId>
	<version>24.1-jre</version>
</dependency>
4.2.2 代码中使用
	public static LoadingCache<Long, User> userCache= CacheBuilder.newBuilder()
            // 缓存池大小,在缓存数量到达该大小时, 开始回收旧的数据
            .maximumSize(1000)
            // 设置时间60s对象没有被读/写访问则对象从内存中删除
            .expireAfterAccess(60, TimeUnit.SECONDS)
            // 设置缓存在写入之后 设定时间60s后失效
            .expireAfterWrite(60, TimeUnit.SECONDS)
            // 定时刷新,设置时间10s后,当有访问时会重新执行load方法重新加载
            .refreshAfterWrite(10, TimeUnit.SECONDS)
            // 移除监听器,缓存项被移除时会触发
            .removalListener(new RemovalListener() {
                @Override
                public void onRemoval(RemovalNotification rn) {
                    // 处理缓存键不存在缓存值时的处理逻辑
                    log.error(rn.getKey() + "remove");
                }
            })
            // 处理缓存键对应的缓存值不存在时的处理逻辑
            .build(new CacheLoader<Long, User>() {
                @Override
                public User load(Long id) {
                    return getById(id);
                }
    });
 
    public User getUser(Long id) {
        User user = userCache.get(id);
    }
 
    public ImmutableMap<Long, User > getAll(List<Long> ids) throws ExecutionException {
        return cache.getAll(ids);
    }
4.2.3 参数说明
 ① maximumSize:缓存的k-v最大数据,当总缓存的数据量达到这个值时,就会淘汰它认为不太用的一份数据,会使用LRU策略进行回收;
 ② expireAfterAccess:缓存项在给定时间内没有被读/写访问,则回收,这个策略主要是为了淘汰长时间不被访问的数据;
 ③ expireAfterWrite:缓存项在给定时间内没有被写访问(创建或覆盖),则回收, 防止旧数据被缓存过久;
 ④ refreshAfterWrite:缓存项在给定时间内没有被写访问(创建或覆盖),则刷新;
 ⑤ recordStats:开启Cache的状态统计(默认是开启的);
4.2.4 GET方法
  V get(K key, int hash, CacheLoader<? super K, V> loader) throws ExecutionException {
    try {
      if (count != 0) { // read-volatile
        ReferenceEntry<K, V> e = getEntry(key, hash);
        if (e != null) {
          long now = map.ticker.read();
          //检查entry是否符合expireAfterAccess淘汰策略
          V value = getLiveValue(e, now);
          // value是有效的 则返回
          if (value != null) {
            // 记录该值的最近访问时间
            recordRead(e, now);
            statsCounter.recordHits(1);
            // 内部实现了定时刷新,若未开启refreshAfterWrite则直接返回value
            return scheduleRefresh(e, key, hash, value, now, loader);
          }
          ValueReference<K, V> valueReference = e.getValueReference();
          // 如果有别的线程已经在load value,则等到其他线程完成后再取结果
          if (valueReference.isLoading()) {
            return waitForLoadingValue(e, key, valueReference);
          }
        }
      }
 
      // 如果没拿到有效的value,则执行加载逻辑;
      return lockedGetOrLoad(key, hash, loader);
    } catch (ExecutionException ee) {
      ...
    } finally {
      postReadCleanup();
    }
  }
4.2.5 Load方法
@GwtCompatible(emulated = true)
public abstract class CacheLoader<K, V> {
 
  public abstract V load(K key) throws Exception;
 
}

在这里插入图片描述

4.3 移除机制

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

  1. 被动移除
  • 基于大小的移除:数量达到指定大小,会把不常用的键值移除
  • 基于时间的移除:expireAfterAccess(long, TimeUnit) 根据某个键值对最后一次访问之后多少时间后移除。expireAfterWrite(long, TimeUnit) 根据某个键值对被创建或值被替换后多少时间移除
  • 基于引用的移除:主要是基于java的垃圾回收机制,根据键或者值的引用关系决定移除
  1. 主动移除
  • 单独移除:Cache.invalidate(key)
  • 批量移除:Cache.invalidateAll(keys)
  • 移除所有:Cache.invalidateAll()

如果配置了移除监听器RemovalListener,则在所有移除的动作时会同步执行该listener下的逻辑。
如需改成异步,使用:RemovalListeners.asynchronous(RemovalListener, Executor)。

4.4 其他

  • 在put操作之前,如果已经有该键值,会先触发removalListener移除监听器,再添加
  • 配置了expireAfterAccess和expireAfterWrite,但在指定时间后没有被移除。
  • 删除策略逻辑:
    CacheBuilder构建的缓存不会在特定时间自动执行清理和回收工作,也不会在某个缓存项过期后马上清理,它不会启动一个线程来进行缓存维护,因为首先线程相对较重,其次某些环境限制线程的创建。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1859434.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【uniapp】HBuilderx中uniapp项目运行到微信小程序报错Error: Fail to open IDE

HBuilderx中uniapp项目运行到微信小程序报错Error: Fail to open IDE 问题描述 uniapp开发微信小程序&#xff0c;在HBuilderx中运行到微信开发者工具时报错Error: Fail to open IDE 解决方案 1. 查看微信开发者工具端服务端口是否开放 打开微信开发者工具选择&#xff1…

艺术家电gorenje x 设计上海丨用设计诠释“生活的艺术”

2024年6月19日—22日&#xff0c;艺术家电gorenje亮相“设计上海”2024&#xff0c;以“gorenje是家电更是艺术品”为题&#xff0c;为人们带来融入日常的艺术之美。设计上海2024不但汇集了国内外卓越设计品牌和杰出独立设计师的家具设计作品&#xff0c;还联合国内外多名设计师…

【linux学习十六】网络管理

网络管理器(NetworkManager)是一个动态网络的控制器与配置系统&#xff0c;它用于当网络设备可用时保持设备和连接开启并激活 默认情况下&#xff0c;CentOS/RHEL7已安装网络管理器&#xff0c;并处于启用状态。 认识网卡 ens32 ens33 ens34 ens35 一.ip相关 查询网络状态 sy…

数据结构——二分算法

二分查找 1. 在排序数组中查找元素的第一个和最后一个位置 代码实现&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/int binarySearch(int *nums, int numsSize, int target) {int l 0, r numsSize - 1; while (l <…

viper:一款中国人写的红队服务器——记一次内网穿透练习

1. viper Viper 是中国人自主编写的一款红队服务器&#xff0c;提供图形化的操作界面&#xff0c;让用户使用浏览器即可进行内网渗透&#xff0c;发布在语雀官方地址 提供了很全面的官方文档&#xff0c;包括四大部分&#xff0c;分别是使用手册、模块文档、博客文章、开发手册…

高中数学:数列-错位相减法与裂项相消法求数列的和

一、错位相减法 设&#xff0c;an是等差数列&#xff0c;bn是等比数列&#xff0c;那么{an*bn}构成一个新的数列 这个新数列的求和公式&#xff0c;就可以用错位相减法求解。 练习 例题1 解析&#xff1a; 第一问 第二问 二、裂项相消法 1、裂项的几种常见形式 形式1…

Junit4测试基本应用(白盒测试)

Junit4测试基本应用&#xff08;白盒测试&#xff09; 一、实验目的 掌握Junit的基本操作&#xff0c;进行较简单的单元测试。 二、Junit4测试的使用 1. 创建java项目JUnitText 我使用的Eclipse&#xff0c;在左侧Package Explorer(包资源管理器)右键&#xff0c;新建Java …

物联网 IoT 收录

物联网IoT日常知识收录 thingsboard, nodered是国际大品牌&#xff0c; iotgateway是国内的&#xff0c; 几个scada, pyscada, json-scada都还不错&#xff0c;比较一下。thingsboard-gateway是python系的&#xff0c;如果你愿意&#xff0c;可以用这个作为公司的物联网网关。…

全网最强剖析Spring AOP底层原理

相信各位读者对于Spring AOP的理解都是一知半解&#xff0c;只懂使用&#xff0c;却不懂原理。网上关于Spring AOP的讲解层出不穷&#xff0c;但是易于理解&#xff0c;让人真正掌握原理的文章屈指可数。笔者针对这一痛点需求&#xff0c;决定写一篇关于Spring AOP原理的优质博…

视频监控解决方案:视频平台升级技术方案(下)

目录 1 项目概况 2 项目需求 2.1 视频感知资源扩充 2.2 视频支撑能力升级 2.3 视频应用能力升级 3 技术设计方案 3.1系统总体架构 3.2视频感知资源扩充设计 3.3 视频支撑能力升级设计 3.4 视频应用能力升级设计 3.4.1视频资源目录管理 3.4.2标签管理 3.4.3设备智能…

万亿国债野外图传——天通卫星图传设备类目推荐

在远离都市喧嚣的辽阔自然中&#xff0c;户外工业作业以其独特的重要性日益凸显&#xff0c;涵盖了从高山峻岭的地质勘探、森林资源调查到广袤草原的生态监测等众多领域。然而传统监测方法不能全面覆盖&#xff0c;冰雪覆盖的山区和偏远地区的电力设施状况以及野生动物等户外状…

多功能推拉力测试机可实现焊球推力测试

LB-8100A 多功能推拉力测试机广泛应于与 LED 封装测试、IC 半导体封 装测试、TO 封装测试、IGBT 功率模块封装测试、光电子元器件封装测试、汽 车领域、航天航空领域、军工产品测试、研究机构的测试及各类院校的测试 研究等应用。 多功能推拉力测试机设置主要结构&#xff1a;…

DDD(data display debugger)调试工具

文章目录 DDD安装界面说明 DDD data display debugger是命令行调试程序&#xff0c;可以理解为可视化的GDB。 安装 CentOS下使用以下命令进行安装&#xff1a; yum install ddd等待安装完成即可。 界面说明 顺便写一个测试程序&#xff0c;编译可执行文件 终端命令行输入…

51单片机STC89C52RC——7.1 串口通信

目的/效果 实现单片机串口与电脑串口工具进行数据通讯&#xff0c; 1&#xff1a;设备向电脑串口发送HEX 2&#xff1a;让电脑串口工具控制单片机LED亮灭。同时让单片机反馈控制的结果。 一&#xff0c;STC单片机模块 二&#xff0c;串口通讯 2.1 串行通信与并行通信 &…

智心顾问:为心智障碍家庭带来温暖与专业支持

&#x1f499;关爱从心开始 —— 理解心智障碍 在这个世界上&#xff0c;有这样一群特殊的群体——心智障碍者。他们通常伴随着个体认知、社会互动和学习能力的障碍。这些障碍可能源于遗传、环境或未知因素&#xff0c;但不应成为他们照护者获得信息和支持的阻碍。心智障碍者的…

webStorm debug vue项目的两种方法

一、前言 本文将介绍通过webstorm对vue项目进行debugger调试的三种方案。 但是&#xff0c;不管通过那种方案&#xff0c;都无法达到类似后端idea调试的体验&#xff0c;感觉十分难受&#xff0c;不过&#xff0c;比起用console.log还是好一些。如果各位有更好的方案&#xf…

【本地知识库】本地知识库+语言大模型=知域问答

本地知识库语言大模型知域问答 本项目实质为本地知识库构建及应用&#xff0c;内容包含&#xff1a; 本地知识库构建及应用相关知识的介绍离线式本地知识库构建及应用在线式本地知识库构建及应用 本地知识库构建及应用相关知识的介绍 本地知识库 本地知识库通常是指存储在…

免费悬浮翻译器都有哪些?看剧学习都适配的翻译器分享~

不知道大家有没有设想过&#xff0c;当我们在查阅外文文档或是观看外语电影时&#xff0c;要是能够借助翻译工具来同步获取译文&#xff0c;那得有多快乐~ 不瞒大家说&#xff0c;现在想要实现这种快乐其实很简单&#xff01;只要手里头备好几个趁手的免费悬浮翻译器就可以搞定…

为冲刺IPO,喜马拉雅曝裁员20%?钉钉叶军吐槽百度搜索;美国制裁俄罗斯安全软件12名高管;华为自研语言仓颉力战Java

一、商业圈 1.钉钉总裁叶军吐槽百度搜索&#xff1a;前十条都是广告 钉钉总裁叶军在亚布力中国企业家论坛第十届创新年会上发表了演讲&#xff0c;期间他直言不讳地对百度搜索提出了批评。叶军指出&#xff0c;在OpenAI推出智能聊天机器人ChatGPT之后&#xff0c;百度的传统搜…

昇思25天学习打卡营第1天|基本介绍

今天的课程内容是MindSpore和昇腾AI全栈的整体介绍。 MindSpore 介绍 全场景深度学习框架 架构结构 扩展部分 Model Zoo 模型库Extend 扩展库&#xff08;强化学习/GNN&#xff09;Sciene 科学计算 开放部分MindExpression 统一API第三方前端 运行部分Data 数据处理AI编译…