当前位置: 首页 > 编程笔记 >

Java缓存Map设置过期时间实现解析

田博远
2023-03-14
本文向大家介绍Java缓存Map设置过期时间实现解析,包括了Java缓存Map设置过期时间实现解析的使用技巧和注意事项,需要的朋友参考一下

这篇文章主要介绍了Java缓存Map设置过期时间实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

前言

最近项目需求需要一个类似于redis可以设置过期时间的K,V存储方式。项目前期暂时不引进redis,暂时用java内存代替。

解决方案

1. ExpiringMap

功能简介 :

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

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

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

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

github地址:https://github.com/jhalterman/expiringmap/

maven添加依赖即可使用

<dependency> 
  <groupId>net.jodah</groupId> 
  <artifactId>expiringmap</artifactId> 
  <version>0.5.8</version> 
</dependency> 
public static void main(String[] args) throws InterruptedException {
    ExpiringMap<String,String> map = ExpiringMap.builder()
        .maxSize(100)
        .expiration(1, TimeUnit.SECONDS)
        .expirationPolicy(ExpirationPolicy.ACCESSED)
        .variableExpiration()
        .build();
    map.put("test","test123");
    Thread.sleep(500);
    String test= map.get("test");
    System.err.println(test);
 }

2.Guava - LoadingCache

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

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

但是该cache不会在特定时间准时回收键值,所以不适用于我当前的业务场景。

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>27.1-jre</version>
</dependency>

 3. ExpiryMap

这是网上某位大佬自己封装的map,继承至HashMap,重写了所有对外的方法,对每个key值都设置了有效期。

我在其基础上增加了使用单例模式获取map。

import java.util.*;

/**
 * @Title: ExpiryMap 可以设置过期时间的Map
 * @description ExpiryMap继承至HashMap 重写了所有对外的方法,对每个key值都设置了有效期
 * @Author: xx
 * @Version: 1.0
 */
public class ExpiryMap<K, V> extends HashMap<K, V> {

  private static final long serialVersionUID = 1L;

  /**
   * default expiry time 2s
   */
  private long EXPIRY = 1000 * 2;

  private HashMap<K, Long> expiryMap = new HashMap<>();

  /** 缓存实例对象 */
  private volatile static ExpiryMap<String, String> SameUrlMap;

  /**
   * 采用单例模式获取实例
   * @return
   */
  public static ExpiryMap getInstance() {
    //第一次判空,提高效率
    if (null == SameUrlMap) {
      //保证线程安全
      synchronized (ExpiryMap.class) {
        //第二次判空,保证单例对象的唯一性,防止第一次有多个线程进入第一个if判断
        if (null == SameUrlMap) {
          SameUrlMap = new ExpiryMap<>();
        }
      }
    }
    return SameUrlMap;
  }

  public ExpiryMap(){
    super();
  }

  public ExpiryMap(long defaultExpiryTime){
    this(1 << 4, defaultExpiryTime);
  }

  public ExpiryMap(int initialCapacity, long defaultExpiryTime){
    super(initialCapacity);
    this.EXPIRY = defaultExpiryTime;
  }

  @Override
  public V put(K key, V value) {
    expiryMap.put(key, System.currentTimeMillis() + EXPIRY);
    return super.put(key, value);
  }

  @Override
  public boolean containsKey(Object key) {
    return !checkExpiry(key, true) && super.containsKey(key);
  }
  /**
   * @param key
   * @param value
   * @param expiryTime 键值对有效期 毫秒
   * @return
   */
  public V put(K key, V value, long expiryTime) {
    expiryMap.put(key, System.currentTimeMillis() + expiryTime);
    return super.put(key, value);
  }

  @Override
  public int size() {
    return entrySet().size();
  }

  @Override
  public boolean isEmpty() {
    return entrySet().size() == 0;
  }

  @Override
  public boolean containsValue(Object value) {
    if (value == null) {
      return Boolean.FALSE;
    }
    Set<Entry<K, V>> set = super.entrySet();
    Iterator<Entry<K, V>> iterator = set.iterator();
    while (iterator.hasNext()) {
      java.util.Map.Entry<K, V> entry = iterator.next();
      if(value.equals(entry.getValue())){
        if(checkExpiry(entry.getKey(), false)) {
          iterator.remove();
          return Boolean.FALSE;
        }else {
          return Boolean.TRUE;
        }
      }
    }
    return Boolean.FALSE;
  }

  @Override
  public Collection<V> values() {

    Collection<V> values = super.values();

    if(values == null || values.size() < 1) {
      return values;
    }

    Iterator<V> iterator = values.iterator();

    while (iterator.hasNext()) {
      V next = iterator.next();
      if(!containsValue(next)) {
        iterator.remove();
      }
    }
    return values;
  }

  @Override
  public V get(Object key) {
    if (key == null) {
      return null;
    }
    if(checkExpiry(key, true)) {
      return null;
    }
    return super.get(key);
  }
  /**
   *
   * @Description: 是否过期
   * @param key
   * @return null:不存在或key为null -1:过期 存在且没过期返回value 因为过期的不是实时删除,所以稍微有点作用
   */
  public Object isInvalid(Object key) {
    if (key == null) {
      return null;
    }
    if(!expiryMap.containsKey(key)){
      return null;
    }
    long expiryTime = expiryMap.get(key);

    boolean flag = System.currentTimeMillis() > expiryTime;

    if(flag){
      super.remove(key);
      expiryMap.remove(key);
      return -1;
    }
    return super.get(key);
  }

  @Override
  public void putAll(Map<? extends K, ? extends V> m) {
    for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
      expiryMap.put(e.getKey(), System.currentTimeMillis() + EXPIRY);
    }
    super.putAll(m);
  }

  @Override
  public Set<Map.Entry<K,V>> entrySet() {
    Set<java.util.Map.Entry<K, V>> set = super.entrySet();
    Iterator<java.util.Map.Entry<K, V>> iterator = set.iterator();
    while (iterator.hasNext()) {
      java.util.Map.Entry<K, V> entry = iterator.next();
      if(checkExpiry(entry.getKey(), false)) {
        iterator.remove();
      }
    }

    return set;
  }
  /**
   *
   * @Description: 是否过期
   * @param expiryTime true 过期
   * @param isRemoveSuper true super删除
   * @return
   */
  private boolean checkExpiry(Object key, boolean isRemoveSuper){

    if(!expiryMap.containsKey(key)){
      return Boolean.FALSE;
    }
    long expiryTime = expiryMap.get(key);

    boolean flag = System.currentTimeMillis() > expiryTime;

    if(flag){
      if(isRemoveSuper) {
        super.remove(key);
      }
      expiryMap.remove(key);
    }
    return flag;
  }

  public static void main(String[] args) throws InterruptedException {
    ExpiryMap<String, String> map = new ExpiryMap<>();
    map.put("test", "xxx");
    map.put("test2", "ankang", 5000);
    System.out.println("test==" + map.get("test"));
    Thread.sleep(3000);
    System.out.println("test==" + map.get("test"));
    System.out.println("test2==" + map.get("test2"));
    Thread.sleep(3000);
    System.out.println("test2==" + map.get("test2"));
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 我无法使用Ehcache设置二级缓存的过期时间 有什么方法可以配置到期时间吗?

  • 本文向大家介绍java设置session过期时间的实现方法,包括了java设置session过期时间的实现方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了java设置session过期时间的实现方法,分享给大家供大家参考。具体实现方法如下: 1、Timeout in the deployment descriptor (web.xml) 以分钟为单位 上面这种设置,对整个web应用生效

  • 本文向大家介绍小程序中设置缓存过期的实现方法,包括了小程序中设置缓存过期的实现方法的使用技巧和注意事项,需要的朋友参考一下 需求是两张图片在这个时间段内交替显示,当天只弹一次图片。 后端返回的数据格式: 小程序中缓存没有过期时间,也就是说存储进去的缓存要自己手动清除,那么如何保证两张图片能够交替显示呢? 需求分析 一天只弹一次广告 图片轮流显示 只在时间范围内显示 这里有个关键是,如何知道时间有没

  • 我们目前正在使用下面的。它很旧,但现在无法升级到更高版本 我们已经将代码从直接JDG实现(如下所示)修改为基于XML的配置文件中的SpringRemteCacheManager,并使用Spring cache:建议来定义可缓存、cahce-put、cache-evict方法。 请参阅当前代码,其中我们可以控制添加到期时间。我们也想用Spring-Infinispan做类似的事情。使用Spring-

  • 本文向大家介绍详解Java实现LRU缓存,包括了详解Java实现LRU缓存的使用技巧和注意事项,需要的朋友参考一下 LRU是Least Recently Used 的缩写,翻译过来就是“最近最少使用”,LRU缓存就是使用这种原理实现,简单的说就是缓存一定量的数据,当超过设定的阈值时就把一些过期的数据删除掉,比如我们缓存10000条数据,当数据小于10000时可以随意添加,当超过10000时就需要把

  • 本文向大家介绍Nginx设置静态页面压缩和缓存过期时间的方法,包括了Nginx设置静态页面压缩和缓存过期时间的方法的使用技巧和注意事项,需要的朋友参考一下 使用nginx服务器的朋友可能都知道需要设置html静态页面缓存与页面压缩与过期时间的设置了,下面我来给各位同学介绍一下配置方法,包括对ico,gif,bmp,jpg,jpeg,swf,js,css,mp3文件进行本地缓存. 可以通过nginx