Java緩存Map設(shè)置過期時(shí)間實(shí)現(xiàn)解析
這篇文章主要介紹了Java緩存Map設(shè)置過期時(shí)間實(shí)現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
前言
最近項(xiàng)目需求需要一個(gè)類似于redis可以設(shè)置過期時(shí)間的K,V存儲(chǔ)方式。項(xiàng)目前期暫時(shí)不引進(jìn)redis,暫時(shí)用java內(nèi)存代替。
解決方案
1. ExpiringMap
功能簡(jiǎn)介 :
1.可設(shè)置Map中的Entry在一段時(shí)間后自動(dòng)過期。
2.可設(shè)置Map最大容納值,當(dāng)?shù)竭_(dá)Maximum size后,再次插入值會(huì)導(dǎo)致Map中的第一個(gè)值過期。
3.可添加監(jiān)聽事件,在監(jiān)聽到Entry過期時(shí)調(diào)度監(jiān)聽函數(shù)。
4.可以設(shè)置懶加載,在調(diào)用get()方法時(shí)創(chuàng)建對(duì)象。
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開源出來的一個(gè)線程安全的本地緩存解決方案。
特點(diǎn):提供緩存回收機(jī)制,監(jiān)控緩存加載/命中情況,靈活強(qiáng)大的功能,簡(jiǎn)單易上手的api
但是該cache不會(huì)在特定時(shí)間準(zhǔn)時(shí)回收鍵值,所以不適用于我當(dāng)前的業(yè)務(wù)場(chǎng)景。
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>27.1-jre</version> </dependency>
3. ExpiryMap
這是網(wǎng)上某位大佬自己封裝的map,繼承至HashMap,重寫了所有對(duì)外的方法,對(duì)每個(gè)key值都設(shè)置了有效期。
我在其基礎(chǔ)上增加了使用單例模式獲取map。
import java.util.*; /** * @Title: ExpiryMap 可以設(shè)置過期時(shí)間的Map * @description ExpiryMap繼承至HashMap 重寫了所有對(duì)外的方法,對(duì)每個(gè)key值都設(shè)置了有效期 * @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<>(); /** 緩存實(shí)例對(duì)象 */ private volatile static ExpiryMap<String, String> SameUrlMap; /** * 采用單例模式獲取實(shí)例 * @return */ public static ExpiryMap getInstance() { //第一次判空,提高效率 if (null == SameUrlMap) { //保證線程安全 synchronized (ExpiryMap.class) { //第二次判空,保證單例對(duì)象的唯一性,防止第一次有多個(gè)線程進(jìn)入第一個(gè)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 鍵值對(duì)有效期 毫秒 * @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 因?yàn)檫^期的不是實(shí)時(shí)刪除,所以稍微有點(diǎn)作用 */ 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")); } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring事務(wù)失效的一種原因關(guān)于this調(diào)用的問題
這篇文章主要介紹了Spring事務(wù)失效的一種原因關(guān)于this調(diào)用的問題,本文給大家分享問題原因及解決辦法,通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-10-10利用MultipartFile實(shí)現(xiàn)文件上傳功能
這篇文章主要為大家詳細(xì)介紹了利用MultipartFile實(shí)現(xiàn)文件上傳功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11Java實(shí)現(xiàn)簡(jiǎn)單推箱子游戲
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)推箱子游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06在mybatis中使用mapper進(jìn)行if條件判斷
這篇文章主要介紹了在mybatis中使用mapper進(jìn)行if條件判斷,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-01-01