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")); } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
上一篇:JavaFX实现拖拽结点效果
栏 目:Java
本文标题:Java缓存Map设置过期时间实现解析
本文地址:https://www.xiuzhanwang.com/a1/Java/8909.html
您可能感兴趣的文章
- 01-10Java实现动态模拟时钟
- 01-10利用Java实现复制Excel工作表功能
- 01-10JavaWeb实现邮件发送功能
- 01-10java基于poi导出excel透视表代码实例
- 01-10Java实现动态数字时钟
- 01-10基于Java验证jwt token代码实例
- 01-10java实现液晶数字字体显示当前时间
- 01-10浅谈Java中真的只有值传递么
- 01-10Java动态显示当前日期和时间
- 01-10如何解决线程太多导致java socket连接池出现的问题
阅读排行
本栏相关
- 01-10Java实现动态模拟时钟
- 01-10Springboot中@Value的使用详解
- 01-10JavaWeb实现邮件发送功能
- 01-10利用Java实现复制Excel工作表功能
- 01-10Java实现动态数字时钟
- 01-10java基于poi导出excel透视表代码实例
- 01-10java实现液晶数字字体显示当前时间
- 01-10基于Java验证jwt token代码实例
- 01-10Java动态显示当前日期和时间
- 01-10浅谈Java中真的只有值传递么
随机阅读
- 08-05dedecms(织梦)副栏目数量限制代码修改
- 01-10C#中split用法实例总结
- 01-11Mac OSX 打开原生自带读写NTFS功能(图文
- 01-10SublimeText编译C开发环境设置
- 04-02jquery与jsp,用jquery
- 01-10delphi制作wav文件的方法
- 08-05DEDE织梦data目录下的sessions文件夹有什
- 01-10使用C语言求解扑克牌的顺子及n个骰子
- 08-05织梦dedecms什么时候用栏目交叉功能?
- 01-11ajax实现页面的局部加载