前言

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

可以设置过期时间的Java缓存Map的更多相关文章

  1. 阿里面试官让我实现一个线程安全并且可以设置过期时间的LRU缓存,我蒙了!

    目录 1. LRU 缓存介绍 2. ConcurrentLinkedQueue简单介绍 3. ReadWriteLock简单介绍 4.ScheduledExecutorService 简单介绍 5. ...

  2. 使用redis事物解决stringRedisTemplate.setIfAbsent()并设置过期时间遇到的问题

    spring-date-redis版本:1.6.2场景:在使用setIfAbsent(key,value)时,想对key设置一个过期时间,同时需要用到setIfAbsent的返回值来指定之后的流程,所 ...

  3. java操作Redis缓存设置过期时间

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

  4. redis 一二事 - 设置过期时间,以文件夹形式展示key显示缓存数据

    在使用redis时,有时回存在大量数据的时候,而且分类相同,ID相同 可以使用hset来设置,这样有一个大类和一个小分类和一个value组成 但是hset不能设置过期时间 过期时间只能在set上设置 ...

  5. redis批量设置过期时间

    Redis 中有删除单个 Key 的指令 DEL,但好像没有批量删除 Key 的指令,不过我们可以借助 Linux 的 xargs 指令来完成这个动作.代码如下: redis-cli keys &qu ...

  6. redis中的key设置过期时间

    EXPIRE key seconds 为给定  key  设置生存时间,当  key  过期时(生存时间为  0  ),它会被自动删除. 在 Redis 中,带有生存时间的  key  被称为『易失的 ...

  7. redis文档翻译_key设置过期时间

    Available since 1.0.0.    使用開始版本号1.01 Time complexity: O(1)  时间复杂度O(1) 出处:http://blog.csdn.net/colum ...

  8. Redis原子性写入HASH结构数据并设置过期时间

    Redis中提供了原子性命令SETEX或SET来写入STRING类型数据并设置Key的过期时间: > SET key value EX NX ok > SETEX key value ok ...

  9. 针对永久不过期的key 批量设置过期时间

    问题需求: redis内存暴增,后来发现有很多设置永久不过期. 解决:查找出来之后针对前缀批量设置过期时间 (过期时间与开发沟通 保证服务不受影响) 来源于网上杨一的代码 正好解决了我遇到的问题 在这 ...

随机推荐

  1. 网际互连__TCP/IP三次握手和四次挥手

    在TCP/IP协议中,TCP协议提供可靠的连接服务. 位码即tcp标志位,有6种标示: SYN(synchronous建立联机).ACK(acknowledgement 确认).PSH(push传送) ...

  2. Java使用反射的通用数组复制方法

    Java通用数组复制方法 在Arrays工具类中,提供了一个copyOf(T[] original, int newLength)方法,用于复制任意类型的对象数组,但是由于泛型不能作用于基本类型,所以 ...

  3. spring源码学习笔记之容器的基本实现(一)

    前言 最近学习了<<Spring源码深度解析>>受益匪浅,本博客是对学习内容的一个总结.分享,方便日后自己复习或与一同学习的小伙伴一起探讨之用. 建议与源码配合使用,效果更嘉, ...

  4. Notepad++ 替换 CRLF 为 LF

    对于文件中每一行的结尾符号,Windows 下默认为 CRLF,而 Unix 下默认为 LF. 所以经常会有这样的情况发生:在 Windows 系统下编辑的文件放在 Unix 下不能正常执行,比如 b ...

  5. Codeforces Round #648 (Div. 2) E. Maximum Subsequence Value(鸽巢原理)

    题目链接:https://codeforces.com/problemset/problem/1365/E 题意 有 $n$ 个元素,定义大小为 $k$ 的集合值为 $\sum2^i$,其中,若集合内 ...

  6. Codeforces Round #646 (Div. 2) A. Odd Selection(数学)

    题目链接:https://codeforces.com/contest/1363/problem/A 题意 判断是否能从 $n$ 个数中选 $x$ 个数加起来和为奇数. 题解 首先 $n$ 个数中至少 ...

  7. Codeforces Round #555 (Div. 3) E. Minimum Array (贪心,二分,set)

    题意:给你两个长度为\(n\)的数组\(a\)和\(b\),元素值在\([0,n-1]\),可以对\(b\)数组的元素任意排序,求新数组\(c\),满足\(c_i=(a_i+b_i)\ mod\ n\ ...

  8. Milk Patterns POJ - 3261 后缀数组

    Farmer John has noticed that the quality of milk given by his cows varies from day to day. On furthe ...

  9. leetcode10 正则表达式匹配 dp

    刚好最近在学编译原理 有点想按照语法分析写..不过用不着 因为知道正则表达式对一个串可能有多种匹配方法,所以要准备好回溯. 有最优子结构,一段s由一段p生成,于是dp. 常规思路是从前开始逐个字符匹配 ...

  10. BZOJ3211 花神游历各国(分块 区间开根号)

    题意:给n个数,可以进行两种操作:给区间[l,r]每个数开方向下取整:算区间[l,r]的和. 思路:我们可以知道,一个数一直开方下去,就会变成0或者1,然后就不会变了.那么当一个区间只剩0或1时,就不 ...