Java緩存Map設(shè)置過期時間實現(xiàn)解析
這篇文章主要介紹了Java緩存Map設(shè)置過期時間實現(xiàn)解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
前言
最近項目需求需要一個類似于redis可以設(shè)置過期時間的K,V存儲方式。項目前期暫時不引進redis,暫時用java內(nèi)存代替。
解決方案
1. ExpiringMap
功能簡介 :
1.可設(shè)置Map中的Entry在一段時間后自動過期。
2.可設(shè)置Map最大容納值,當?shù)竭_Maximum size后,再次插入值會導(dǎo)致Map中的第一個值過期。
3.可添加監(jiān)聽事件,在監(jiān)聽到Entry過期時調(diào)度監(jiān)聽函數(shù)。
4.可以設(shè)置懶加載,在調(diào)用get()方法時創(chuàng)建對象。
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開源出來的一個線程安全的本地緩存解決方案。
特點:提供緩存回收機制,監(jiān)控緩存加載/命中情況,靈活強大的功能,簡單易上手的api
但是該cache不會在特定時間準時回收鍵值,所以不適用于我當前的業(yè)務(wù)場景。
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>27.1-jre</version> </dependency>
3. ExpiryMap
這是網(wǎng)上某位大佬自己封裝的map,繼承至HashMap,重寫了所有對外的方法,對每個key值都設(shè)置了有效期。
我在其基礎(chǔ)上增加了使用單例模式獲取map。
import java.util.*;
/**
* @Title: ExpiryMap 可以設(shè)置過期時間的Map
* @description ExpiryMap繼承至HashMap 重寫了所有對外的方法,對每個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<>();
/** 緩存實例對象 */
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"));
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring事務(wù)失效的一種原因關(guān)于this調(diào)用的問題
這篇文章主要介紹了Spring事務(wù)失效的一種原因關(guān)于this調(diào)用的問題,本文給大家分享問題原因及解決辦法,通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2021-10-10

