Java使用map實現(xiàn)帶過期時間的緩存機制
引言
在 Java 開發(fā)領(lǐng)域,緩存機制的構(gòu)建通常依賴于 Redis 等專業(yè)緩存數(shù)據(jù)庫。這類解決方案雖能提供強大的緩存能力,但引入中間件意味著增加系統(tǒng)架構(gòu)復(fù)雜度、部署成本與運維負(fù)擔(dān)。本文將深入探討一種輕量級替代方案 —— 基于 Java 原生Map實現(xiàn)的帶過期時間的緩存機制。該方案無需引入外部工具,僅依托 Java 標(biāo)準(zhǔn)庫即可快速搭建起緩存體系,特別適用于對資源占用敏感、架構(gòu)追求極簡的項目場景,為開發(fā)者提供了一種輕量高效的緩存數(shù)據(jù)管理新選擇。
優(yōu)點:
- 輕量便捷:無需引入 Redis 等外部中間件,直接使用 Java 標(biāo)準(zhǔn)庫即可實現(xiàn),降低了項目依賴,簡化了部署流程。
- 快速搭建:基于熟悉的Map數(shù)據(jù)結(jié)構(gòu),開發(fā)人員能夠快速理解和實現(xiàn)緩存邏輯,顯著提升開發(fā)效率。
- 資源可控:可靈活控制緩存數(shù)據(jù)的生命周期,通過設(shè)置過期時間,精準(zhǔn)管理內(nèi)存占用,適合對資源占用敏感的場景。
缺點:該方案存在明顯局限性,即數(shù)據(jù)無法持久化。一旦應(yīng)用程序停止運行,緩存中的所有數(shù)據(jù)都會丟失。相較于 Redis 等具備持久化功能的專業(yè)緩存數(shù)據(jù)庫,在需要長期保存緩存數(shù)據(jù),或是應(yīng)對應(yīng)用重啟后數(shù)據(jù)恢復(fù)需求的場景下,基于 Java 原生Map的緩存機制就顯得力不從心。
代碼實現(xiàn)
package com.sunny.utils;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class SysCache {
// 單例實例
private static class Holder {
private static final SysCache INSTANCE = new SysCache();
}
public static SysCache getInstance() {
return Holder.INSTANCE;
}
// 緩存存儲結(jié)構(gòu),Key為String,Value為包含值和過期時間的CacheEntry對象
private final ConcurrentHashMap<String, CacheEntry> cacheMap = new ConcurrentHashMap<>();
// 定時任務(wù)執(zhí)行器
private final ScheduledExecutorService scheduledExecutorService;
// 私有構(gòu)造方法,初始化定時清理任務(wù)
private SysCache() {
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
// 每隔1秒執(zhí)行一次清理任務(wù)
scheduledExecutorService.scheduleAtFixedRate(this::cleanUp, 1, 1, TimeUnit.SECONDS);
// 注冊JVM關(guān)閉鉤子以優(yōu)雅關(guān)閉線程池
Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
}
/**
* 存入緩存
* @param key 鍵
* @param value 值
*/
public void set(String key, Object value){
cacheMap.put(key, new CacheEntry(value, -1));
}
/**
* 存入緩存
* @param key 鍵
* @param value 值
* @param expireTime 過期時間,單位毫秒
*/
public void set(String key, Object value, long expireTime) {
if (expireTime <= 0) {
throw new IllegalArgumentException("expireTime must be greater than 0");
}
cacheMap.put(key, new CacheEntry(value, System.currentTimeMillis() + expireTime));
}
/**
* 刪除緩存
* @param key 鍵
*/
public void remove(String key) {
cacheMap.remove(key);
}
/**
* 緩存中是否包含鍵
* @param key 鍵
*/
public boolean containsKey(String key) {
CacheEntry cacheEntry = cacheMap.get(key);
if (cacheEntry == null) {
return false;
}
if (cacheEntry.getExpireTime() < System.currentTimeMillis()) {
remove(key);
return false;
}
return true;
}
/**
*獲取緩存值
* @param key 鍵
*/
public Object get(String key) {
CacheEntry cacheEntry = cacheMap.get(key);
if (cacheEntry == null) {
return null;
}
if (cacheEntry.getExpireTime() < System.currentTimeMillis()) {
cacheMap.remove(key);
return null;
}
return cacheEntry.getValue();
}
private static class CacheEntry {
private final Object value;
private final long expireTime;
public CacheEntry(Object value, long expireTime) {
this.value = value;
this.expireTime = expireTime;
}
public Object getValue() {
return value;
}
public long getExpireTime() {
return expireTime;
}
}
/**
* 定時清理過期條目
*/
private void cleanUp() {
Iterator<Map.Entry<String, CacheEntry>> iterator = cacheMap.entrySet().iterator();
long currentTime = System.currentTimeMillis();
while (iterator.hasNext()) {
Map.Entry<String, CacheEntry> entry = iterator.next();
CacheEntry cacheEntry = entry.getValue();
if (cacheEntry.expireTime < currentTime) {
// 使用iterator移除當(dāng)前條目,避免ConcurrentModificationException
iterator.remove();
}
}
}
/**
* 關(guān)閉線程池釋放資源
*/
private void shutdown() {
scheduledExecutorService.shutdown();
try {
if (!scheduledExecutorService.awaitTermination(5, TimeUnit.SECONDS)) {
scheduledExecutorService.shutdownNow();
}
} catch (InterruptedException e) {
scheduledExecutorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
測試

如上圖,緩存中放入一個值,過期時間為5秒,每秒循環(huán)獲取1次,循環(huán)10次,過期后,獲取的值為null
到此這篇關(guān)于Java使用map實現(xiàn)帶過期時間的緩存機制的文章就介紹到這了,更多相關(guān)Java map過期時間緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java日期工具類操作字符串Date和LocalDate互轉(zhuǎn)
這篇文章主要介紹了Java日期工具類操作字符串Date和LocalDate互轉(zhuǎn),文章首先通過需要先引入坐標(biāo)展開主題的相關(guān)內(nèi)容介紹,需要的朋友可以參一下2022-06-06

