1. 程式人生 > >Java ConcurrentHashmap實現Localcache本地快取

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]的具體實現。     以上-