Java快取Map設定過期時間實現解析
阿新 • • 發佈:2020-01-07
這篇文章主要介紹了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> 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")); } }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。