前言

  最近项目需求需要一个类似于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

转载于:https://www.cnblogs.com/xhq1024/p/11115755.html

可以设置过期时间的Java缓存Map相关推荐

  1. 如何用java操作Redis缓存设置过期时间

    如何用java操作Redis缓存设置过期时间?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获. 在应用中我们会需要使用red ...

  2. redis缓存失效时间设为多少_java操作Redis缓存设置过期时间的方法

    关于Redis的概念和应用本文就不再详解了,说一下怎么在java应用中设置过期时间. 在应用中我们会需要使用redis设置过期时间,比如单点登录中我们需要随机生成一个token作为key,将用户的信息 ...

  3. java redis设置过期时间_Redis的一些核心原理

    点关注,不迷路:持续更新Java相关技术及资讯!!! 一.Redis的单线程和高性能 Redis 单线程为什么还能这么快? 因为它所有的数据都在内存中,所有的运算都是内存级别的运算(纳秒),而且单线程 ...

  4. java如何保证redis设置过期时间的原子性_2020年4月Redis面试题和答案整理

    点关注,不迷路:持续更新Java相关技术及资讯!!! 关注.转发.评论头条号每天分享java 知识,私信回复"源码" 赠送Spring源码分析.Dubbo.Redis.Netty. ...

  5. @cacheable 设置过期时间_缓存面试三连击——聊聊Redis过期策略?内存淘汰机制?再手写一个LRU 吧!...

    大家好,今天我和大家想聊一聊有关redis的过期策略的话题. 听到这里你也许会觉得:"我去,我只是个日常搬砖的,这种偏底层的知识点,我需要care吗?" 话虽如此·,但是兄die, ...

  6. spring缓存注解@Cacheable和@CacheEvict,设置过期时间和批量模糊删除

    spring缓存注解@Cacheable和@CacheEvict,设置过期时间和批量模糊删除 配置 CacheManager 类 key前缀配置 RedisCache配置 RedisCache 模糊匹 ...

  7. springboot缓存@Cacheable的使用,及设置过期时间

    1,在启动类Application中增加注解@EnableCaching 2,待缓存的方法上方增加@Cacheable注解 @Cacheable(cacheNames = redisContains. ...

  8. java如何保证redis设置过期时间的原子性_分布式锁用 Redis 还是 Zookeeper

    在讨论这个问题之前,我们先来看一个业务场景: 系统A是一个电商系统,目前是一台机器部署,系统中有一个用户下订单的接口,但是用户下订单之前一定要去检查一下库存,确保库存足够了才会给用户下单. 由于系统有 ...

  9. Redis 缓存回收的7种策略volatile设置过期时间及allkeys所有数据范围内

    1.基础说明 当redis设置内存使用限制后,当达到内存限制时,Redis将尝试删除key(控制节点的最大使用内存) redis.conf中配置项maxmemory <bytes>或者控制 ...

最新文章

  1. 问题 “No mapping found for HTTP request with URI [/fileupload/upload.do]” 的解决
  2. 配置Vlan访问控制
  3. insert返回主键 — mybatis selectKey
  4. Spring.NET学习笔记12——面向切面编程(基础篇) Level 300
  5. 无聊的一天_一人互联网公司背后的无聊技术
  6. 管理项目的问题跟踪器的提示
  7. 计算机桌面图标有箭头,电脑桌面图标为什么会有一个小箭头,原来没的呀,
  8. 【Spring 】Synchronized锁在Spring事务管理下,为啥还线程不安全?
  9. C++之构造函数、(构造)函数重载探究
  10. 超分辨率技术如何发展?这6篇ECCV 18论文带你一次尽览
  11. JXLS 2.4.0学习
  12. 内层元素设置position:relative后父元素overflow:hidden overflow:scroll失效 解决方法
  13. python编程从入门到实战1-3章
  14. 新版DAEMON Tools Lite打不开 bin 文件解决方法
  15. docker仓库的搭建居然只要一分钟!
  16. Android仿微信添加联系人列表,内附有截图和demo源码
  17. CTeX 自动化学报模板使用
  18. yii2 如何用命名空间方式使用第三方类库
  19. 传统企业建企业网站应当懂得借助外力
  20. LDO参数解读、特性、参考设计

热门文章

  1. 新Macbook入手后必安装的好用的软件
  2. [译] State of Vue.js report 2017 中文版
  3. centos7部署prometheus+exporter+grafana+Alertmanager+企业微信
  4. P1017 进制转换 (洛谷)
  5. 文件名目录名或卷标语法不正确怎么修复?
  6. 搜索网站/论坛内容帖子
  7. Java中级面试题及答案解析(4)
  8. hive表新增字段和字段注释修改
  9. 【渝粤题库】陕西师范大学111119 统计学作业
  10. 信息系统开发与管理【四】之 总体规划