可以设置过期时间的Java缓存Map

zz/2024/6/13 22:21:01

前言

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


http://www.ngui.cc/zz/2390161.html

相关文章

后端技术杂谈4:Elasticsearch与solr入门实践

阮一峰&#xff1a;全文搜索引擎 Elasticsearch 入门教程 阅读 1093收藏 762017-08-23原文链接&#xff1a;www.ruanyifeng.com9月7日-8日 北京&#xff0c;与 Google Twitch 等团队技术大咖面对面www.bagevent.com 全文搜索属于最常见的需求&#xff0c;开源的 Elasticsearch …

第25章 JDBC核心技术第4节:操作BLOB类型字段

4.1 MySQL BLOB类型 MySQL中&#xff0c;BLOB是一个二进制大型对象&#xff0c;是一个可以存储大量数据的容器&#xff0c;它能容纳不同大小的数据。 插入BLOB类型的数据必须使用PreparedStatement&#xff0c;因为BLOB类型的数据无法使用字符串拼接写的。 MySQL的四种BLOB类…

Java学习个人总结

声明&#xff1a;个人原创&#xff0c;转载请在文章开头明显位置注明出处&#xff1a;https://www.cnblogs.com/sunshine5683/p/10063960.html 学习从来都是一个阶段的学习&#xff0c;然后进行整理与总结&#xff0c;最后才能形成自己的东西&#xff0c;今天将最近所学习的内容…

(翻译自用)TG^2———IJDAR杂志论文

TG2: 用于恢复文档可读性和感知质量的文本引导转换器GAN 摘要 大多数侧重于数字化文本文档恢复的图像增强方法仅限于文本信息仍保留在输入图像中的情况&#xff0c;而这种情况可能通常不是这样。在这项工作中&#xff0c;我们提出了一种新的生成性文档恢复方法&#xff0c;该…

基于Kubernetes/K8S构建Jenkins持续集成平台(一)

目录 Kubernetes实现Master-Slave分布式构建方案 传统Jenkins的Master-Slave方案的缺陷 KubernatesDockerJenkins持续集成架构图 KubernatesDockerJenkins持续集成方案好处 NFS简介 在Kubernetes安装Jenkins-Master 创建nfs-client-rbac 创建NFS client provisioner 创建 nfs…

中国汽水制造商市场趋势报告、技术动态创新及市场预测

汽水制造商市场的企业竞争态势 该报告涉及的主要国际市场参与者有SodaStream、Bonne、Flavorstation、Hamilton Beach、Drinkmate、iSODA、Cuisinart、Delight、Fizz Giz、Frostte、Jaybrake、KitchenAid、KOBWA、Leegoal、Lourdes、Lucky Sports、New、Primo Flavorstation、S…

mysql日志备份命令是什么_mysql的常用命令以及备份和恢复

首先建立一个计划并严格遵守&#xff0c;定期实施备份。让服务器执行更新日志。当你在崩溃后需要恢复数据时&#xff0c;更新日志将帮助你。在你用备份文件恢复数据到备份时的状态后&#xff0c;你可以通过运行更新日志中的查询再次运用备份后面的修改&#xff0c;这将数据库中…

数据结构线性表(1)

顺序表C语言代码实现 实验要求&#xff1a;编写一个头文件SqList.h&#xff0c;实现顺序表的各种基本操作&#xff0c;并在此基础上设计一个主程序&#xff08;exp2_1.cpp&#xff09;完成如下功能&#xff1a; &#xff08;1&#xff09; 初始化顺序表L &#xff08;2&#xf…

chromium浏览器开发系列第一篇:如何获取最新chromium源码

背景&#xff1a; 最近摊上一个事儿&#xff0c;领导非要让写一篇技术文章&#xff0c;思来想去&#xff0c;自己接触chrome浏览器时间也不短了&#xff0c;干脆就总结一下吧。于是乎&#xff0c;本文顺理成章。由于有些细节必需描述清楚&#xff0c;所以这次先讲如何拿到…

中文域名,网站,启用,弘勇,xn--2gr99z.xn--fiqs8s,网址,中国,

下面这些网站是中文域名网站&#xff0c;中文域名直达网站&#xff0c;用百度要搜索关键词&#xff0c;步骤比较多&#xff0c;输入网址比较快&#xff0c;直达网站。还有一些中文域名网站&#xff0c;签名&#xff1a;游志勇。 弘勇.中国&#xff0c; xn–2gr99z.xn–fiqs8s …