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í)有所幫助,也希望大家多多支持我們。
上一篇:JavaFX實(shí)現(xiàn)拖拽結(jié)點(diǎn)效果
欄 目:Java
本文標(biāo)題:Java緩存Map設(shè)置過期時(shí)間實(shí)現(xiàn)解析
本文地址:http://www.jygsgssxh.com/a1/Java/8909.html
您可能感興趣的文章
- 01-10Java實(shí)現(xiàn)動(dòng)態(tài)模擬時(shí)鐘
- 01-10利用Java實(shí)現(xiàn)復(fù)制Excel工作表功能
- 01-10JavaWeb實(shí)現(xiàn)郵件發(fā)送功能
- 01-10java基于poi導(dǎo)出excel透視表代碼實(shí)例
- 01-10Java實(shí)現(xiàn)動(dòng)態(tài)數(shù)字時(shí)鐘
- 01-10基于Java驗(yàn)證jwt token代碼實(shí)例
- 01-10java實(shí)現(xiàn)液晶數(shù)字字體顯示當(dāng)前時(shí)間
- 01-10淺談Java中真的只有值傳遞么
- 01-10Java動(dòng)態(tài)顯示當(dāng)前日期和時(shí)間
- 01-10如何解決線程太多導(dǎo)致java socket連接池出現(xiàn)的問題


閱讀排行
- 1C語言 while語句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10Java實(shí)現(xiàn)動(dòng)態(tài)模擬時(shí)鐘
- 01-10Springboot中@Value的使用詳解
- 01-10JavaWeb實(shí)現(xiàn)郵件發(fā)送功能
- 01-10利用Java實(shí)現(xiàn)復(fù)制Excel工作表功能
- 01-10Java實(shí)現(xiàn)動(dòng)態(tài)數(shù)字時(shí)鐘
- 01-10java基于poi導(dǎo)出excel透視表代碼實(shí)例
- 01-10java實(shí)現(xiàn)液晶數(shù)字字體顯示當(dāng)前時(shí)間
- 01-10基于Java驗(yàn)證jwt token代碼實(shí)例
- 01-10Java動(dòng)態(tài)顯示當(dāng)前日期和時(shí)間
- 01-10淺談Java中真的只有值傳遞么
隨機(jī)閱讀
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 04-02jquery與jsp,用jquery
- 01-10delphi制作wav文件的方法
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11ajax實(shí)現(xiàn)頁面的局部加載


