zoukankan      html  css  js  c++  java
  • 可以设置过期时间的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不会在特定时间准时回收键值,所以不适用于我当前的业务场景。

      详细描述介绍看我的另外一篇博客:https://www.cnblogs.com/xhq1024/p/11174775.html

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

        3. ExpiryMap

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

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

      1 import java.util.*;
      2 
      3 /**
      4  * @Title: ExpiryMap 可以设置过期时间的Map
      5  * @description ExpiryMap继承至HashMap 重写了所有对外的方法,对每个key值都设置了有效期
      6  * @Author: xx
      7  * @Version: 1.0
      8  */
      9 public class ExpiryMap<K, V> extends HashMap<K, V> {
     10 
     11     private static final long serialVersionUID = 1L;
     12 
     13     /**
     14      * default expiry time 2s
     15      */
     16     private long EXPIRY = 1000 * 2;
     17 
     18     private HashMap<K, Long> expiryMap = new HashMap<>();
     19 
     20     /**  缓存实例对象 */
     21     private volatile static ExpiryMap<String, String> SameUrlMap;
     22 
     23     /**
     24      * 采用单例模式获取实例
     25      * @return
     26      */
     27     public static ExpiryMap getInstance() {
     28         //第一次判空,提高效率
     29         if (null == SameUrlMap) {
     30             //保证线程安全
     31             synchronized (ExpiryMap.class) {
     32                 //第二次判空,保证单例对象的唯一性,防止第一次有多个线程进入第一个if判断
     33                 if (null == SameUrlMap) {
     34                     SameUrlMap = new ExpiryMap<>();
     35                 }
     36             }
     37         }
     38         return SameUrlMap;
     39     }
     40 
     41     public ExpiryMap(){
     42         super();
     43     }
     44 
     45     public ExpiryMap(long defaultExpiryTime){
     46         this(1 << 4, defaultExpiryTime);
     47     }
     48 
     49     public ExpiryMap(int initialCapacity, long defaultExpiryTime){
     50         super(initialCapacity);
     51         this.EXPIRY = defaultExpiryTime;
     52     }
     53 
     54     @Override
     55     public V put(K key, V value) {
     56         expiryMap.put(key, System.currentTimeMillis() + EXPIRY);
     57         return super.put(key, value);
     58     }
     59 
     60     @Override
     61     public boolean containsKey(Object key) {
     62         return !checkExpiry(key, true) && super.containsKey(key);
     63     }
     64     /**
     65      * @param key
     66      * @param value
     67      * @param expiryTime 键值对有效期 毫秒
     68      * @return
     69      */
     70     public V put(K key, V value, long expiryTime) {
     71         expiryMap.put(key, System.currentTimeMillis() + expiryTime);
     72         return super.put(key, value);
     73     }
     74 
     75     @Override
     76     public int size() {
     77         return entrySet().size();
     78     }
     79 
     80     @Override
     81     public boolean isEmpty() {
     82         return entrySet().size() == 0;
     83     }
     84 
     85     @Override
     86     public boolean containsValue(Object value) {
     87         if (value == null) {
     88             return Boolean.FALSE;
     89         }
     90         Set<Entry<K, V>> set = super.entrySet();
     91         Iterator<Entry<K, V>> iterator = set.iterator();
     92         while (iterator.hasNext()) {
     93             java.util.Map.Entry<K, V> entry = iterator.next();
     94             if(value.equals(entry.getValue())){
     95                 if(checkExpiry(entry.getKey(), false)) {
     96                     iterator.remove();
     97                     return Boolean.FALSE;
     98                 }else {
     99                     return Boolean.TRUE;
    100                 }
    101             }
    102         }
    103         return Boolean.FALSE;
    104     }
    105 
    106     @Override
    107     public Collection<V> values() {
    108 
    109         Collection<V> values = super.values();
    110 
    111         if(values == null || values.size() < 1) {
    112             return values;
    113         }
    114 
    115         Iterator<V> iterator = values.iterator();
    116 
    117         while (iterator.hasNext()) {
    118             V next = iterator.next();
    119             if(!containsValue(next)) {
    120                 iterator.remove();
    121             }
    122         }
    123         return values;
    124     }
    125 
    126     @Override
    127     public V get(Object key) {
    128         if (key == null) {
    129             return null;
    130         }
    131         if(checkExpiry(key, true)) {
    132             return null;
    133         }
    134         return super.get(key);
    135     }
    136     /**
    137      *
    138      * @Description: 是否过期
    139      * @param key
    140      * @return null:不存在或key为null -1:过期  存在且没过期返回value 因为过期的不是实时删除,所以稍微有点作用
    141      */
    142     public Object isInvalid(Object key) {
    143         if (key == null) {
    144             return null;
    145         }
    146         if(!expiryMap.containsKey(key)){
    147             return null;
    148         }
    149         long expiryTime = expiryMap.get(key);
    150 
    151         boolean flag = System.currentTimeMillis() > expiryTime;
    152 
    153         if(flag){
    154             super.remove(key);
    155             expiryMap.remove(key);
    156             return -1;
    157         }
    158         return super.get(key);
    159     }
    160 
    161     @Override
    162     public void putAll(Map<? extends K, ? extends V> m) {
    163         for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
    164             expiryMap.put(e.getKey(), System.currentTimeMillis() + EXPIRY);
    165         }
    166         super.putAll(m);
    167     }
    168 
    169     @Override
    170     public Set<Map.Entry<K,V>> entrySet() {
    171         Set<java.util.Map.Entry<K, V>> set = super.entrySet();
    172         Iterator<java.util.Map.Entry<K, V>> iterator = set.iterator();
    173         while (iterator.hasNext()) {
    174             java.util.Map.Entry<K, V> entry = iterator.next();
    175             if(checkExpiry(entry.getKey(), false)) {
    176                 iterator.remove();
    177             }
    178         }
    179 
    180         return set;
    181     }
    182     /**
    183      *
    184      * @Description: 是否过期
    185      * @param expiryTime true 过期
    186      * @param isRemoveSuper true super删除
    187      * @return
    188      */
    189     private boolean checkExpiry(Object key, boolean isRemoveSuper){
    190 
    191         if(!expiryMap.containsKey(key)){
    192             return Boolean.FALSE;
    193         }
    194         long expiryTime = expiryMap.get(key);
    195 
    196         boolean flag = System.currentTimeMillis() > expiryTime;
    197 
    198         if(flag){
    199             if(isRemoveSuper) {
    200                 super.remove(key);
    201             }
    202             expiryMap.remove(key);
    203         }
    204         return flag;
    205     }
    206 
    207     public static void main(String[] args) throws InterruptedException {
    208         ExpiryMap<String, String> map = new ExpiryMap<>();
    209         map.put("test", "xxx");
    210         map.put("test2", "ankang", 5000);
    211         System.out.println("test==" + map.get("test"));
    212         Thread.sleep(3000);
    213         System.out.println("test==" + map.get("test"));
    214         System.out.println("test2==" + map.get("test2"));
    215         Thread.sleep(3000);
    216         System.out.println("test2==" + map.get("test2"));
    217     }
    218 }

    附上ExpiryMap原文地址:https://blog.csdn.net/u011534095/article/details/54091337

  • 相关阅读:
    Servlet学习小结
    HTTP学习小结
    SpringMVC第二天
    使用Servlet 编写过滤器
    项目使用框架
    java-web
    SSM框架集成.下(供自己练习查阅用)
    SSM框架集成.中(供自己练习查阅用)
    SSM框架集成.上(供自己练习查阅用)
    debug
  • 原文地址:https://www.cnblogs.com/xhq1024/p/11115755.html
Copyright © 2011-2022 走看看