Java ConcurrentHashmap實現Localcache本地快取
很多場景下,有些請求的資料,是不會經常改變的,這種時候,為了減少資料庫的查詢壓力,可以將這一部分資料放入快取中,直接從快取中讀取。除了一些像Redis等快取外,還可以通過本地記憶體,作為快取。下邊將使用ConcurrentHashMap來實現本地快取。 >相關的技術: - ConcurrentHashMap --資料儲存,執行緒安全的map - ScheduledExecutorService --執行緒定時排程服務 - TimerTask --定時任務 - lambda表示式 >整體思路 1.用執行緒安全的ConcurrentHashMap來作為快取資料的儲存, 2.然後通過定時排程任務TimerTask,來實現控制快取的有效時間,根據快取設定的超時時間,來定時清除對應的 key, 實現快取過期 3.實現一些靜態方法,來增加快取、獲取快取等 >定時任務也可也以用Timer來進行排程,但是Timer與ScheduledExecutorService相比有一些 >缺陷,具體對比,可以另行檢視。 1.多執行緒並行處理定時任務時,Timer執行多個TimeTask時,只要其中之一沒有捕獲丟擲的異常其它任務便會自動終止執行, 使用ScheduledExecutorService則沒有這個問題 2.Timer內部是一個執行緒,任務1所需的時間超過了兩個任務間的間隔時會導致問題 3.Timer執行週期任務時依賴系統時間 >LocalCache整體結構
> 初始化資料
```
/**
* 預設快取時長 單位s
*/
private static final int DEFAULT_TIMEOUT = 3600;
/**
* 預設快取容量
*/
private static final int DEFAULT_SIZE = 1000;
/**
* 儲存資料
*/
private static final Map<String,Object> data;
private static final ScheduledExecutorService executorService;
//初始化
static {
data = new ConcurrentHashMap<>(DEFAULT_SIZE);
executorService = new ScheduledThreadPoolExecutor(2);
}
/**
* 私有化建構函式
*/
private LocalCache(){}
```
>刪除快取的定時任務
定時任務主要是實現TimerTask類中的run方法,傳入對應的key,然後從快取中移除對應的鍵值對,所以實現方式有三種:靜態內部類、匿名內部類、以及lambda方式,選擇熟悉的一種即可
```
//靜態內部類
static class CacheCleanTask extends TimerTask {
private String key;
private CacheCleanTask(String key){
this.key = key;
}
public static CacheCleanTask cacheTask(String key){
return new CacheCleanTask(key);
}
@Override
public void run() {
//移除對應 key
LocalCache.remove(key);
}
}
```
>增加快取
```
/**
* 增加快取 預設有效時長
* @param key
* @param value
*/
public static void put(String key, Object value){
data.put(key,value);
//定時器 排程任務,用於根據 時間 定時清除 對應key 快取
executorService.schedule(new TimerTask() {
@Override
public void run() {
remove(key);
}
}, DEFAULT_TIMEOUT, TimeUnit.SECONDS);
}
/**
* 增加快取 並設定快取時長 單位 s
* @param key
* @param value
* @param timeout 快取時長 單位s
*/
public static void put(String key, Object value, int timeout){
data.put(key, value);
//lambda 替換匿名內部類
executorService.schedule(() -> remove(key), timeout, TimeUnit.SECONDS);
}
```
>獲取快取
```
/**
* 獲取快取
* @param key
* @return
*/
public static Object get(String key){
return data.get(key);
}
/**
* 獲取當前快取中 所有的key
* @return
*/
public static Set<String> cacheKeys(){
return data.keySet();
}
```
>刪除快取
```
/**
* 刪除快取
* @param key
*/
public static void remove(String key){
data.remove(key);
}
/**
* 清空所有快取
*/
public static void clear(){
if(size() > 0){
data.clear();
}
}
```
測試方法就不貼了,其他更多相關方法的實現,可以看一下[Github](https://github.com/liuyuanju7/Web-Crawler/tree/master/wangyiyun/src/main/java/com/liuyj/core/cache)[https://github.com/liuyuanju7/Web-Crawler/tree/master/wangyiyun/src/main/java/com/liuyj/core/cache]的具體實現。
以上-