使用 ConcurrentHashMap 實(shí)現(xiàn)一個(gè)本地緩存服務(wù)薇搁,系統(tǒng) 快多了

很多場(chǎng)景下,有些請(qǐng)求的數(shù)據(jù)渡八,是不會(huì)經(jīng)常改變的啃洋,這種時(shí)候,為了減少數(shù)據(jù)庫(kù)的查詢壓力屎鳍,可以將這一部分?jǐn)?shù)據(jù)放入緩存中宏娄,直接從緩存中讀取。除了一些像Redis等緩存外逮壁,還可以通過本地內(nèi)存绝编,作為緩存。下邊將使用ConcurrentHashMap來實(shí)現(xiàn)本地緩存貌踏。

相關(guān)的技術(shù):

  • ConcurrentHashMap --數(shù)據(jù)存儲(chǔ)十饥,線程安全的map
  • ScheduledExecutorService --線程定時(shí)調(diào)度服務(wù)
  • TimerTask --定時(shí)任務(wù)
  • lambda表達(dá)式

整體思路

  1. 用線程安全的ConcurrentHashMap來作為緩存數(shù)據(jù)的存儲(chǔ),
  2. 然后通過定時(shí)調(diào)度任務(wù)TimerTask祖乳,來實(shí)現(xiàn)控制緩存的有效時(shí)間逗堵,根據(jù)緩存設(shè)置的超時(shí)時(shí)間,來定時(shí)清除對(duì)應(yīng)的 key眷昆,實(shí)現(xiàn)緩存過期
  3. 實(shí)現(xiàn)一些靜態(tài)方法蜒秤,來增加緩存汁咏、獲取緩存等

定時(shí)任務(wù)也可也以用Timer來進(jìn)行調(diào)度,但是Timer與ScheduledExecutorService相比有一些缺陷作媚,具體對(duì)比攘滩,可以另行查看。

  1. 多線程并行處理定時(shí)任務(wù)時(shí)纸泡,Timer運(yùn)行多個(gè)TimeTask時(shí)漂问,只要其中之一沒有捕獲拋出的異常其它任務(wù)便會(huì)自動(dòng)終止運(yùn)行,使用ScheduledExecutorService則沒有這個(gè)問題
  2. Timer內(nèi)部是一個(gè)線程女揭,任務(wù)1所需的時(shí)間超過了兩個(gè)任務(wù)間的間隔時(shí)會(huì)導(dǎo)致問題
  3. Timer執(zhí)行周期任務(wù)時(shí)依賴系統(tǒng)時(shí)間

LocalCache整體結(jié)構(gòu)

image.png

初始化數(shù)據(jù)

  /**
     * 默認(rèn)緩存時(shí)長(zhǎng) 單位s
     */
    private static final int DEFAULT_TIMEOUT = 3600;
    /**
     * 默認(rèn)緩存容量
     */
    private static final int DEFAULT_SIZE = 1000;

    /**
     * 存儲(chǔ)數(shù)據(jù)
     */
    private static final Map<String,Object> data;

    private static final ScheduledExecutorService executorService;

    //初始化
    static {
        data = new ConcurrentHashMap<>(DEFAULT_SIZE);
        executorService = new ScheduledThreadPoolExecutor(2);
    }
   /**
     * 私有化構(gòu)造函數(shù)
     */
    private LocalCache(){}

刪除緩存的定時(shí)任務(wù)

定時(shí)任務(wù)主要是實(shí)現(xiàn)TimerTask類中的run方法蚤假,傳入對(duì)應(yīng)的key,然后從緩存中移除對(duì)應(yīng)的鍵值對(duì)吧兔,所以實(shí)現(xiàn)方式有三種:靜態(tài)內(nèi)部類磷仰、匿名內(nèi)部類、以及l(fā)ambda方式境蔼,選擇熟悉的一種即可

//靜態(tài)內(nèi)部類
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() {
        //移除對(duì)應(yīng) key
        LocalCache.remove(key);
    }
}

增加緩存

/**
 * 增加緩存 默認(rèn)有效時(shí)長(zhǎng)
 * @param key
 * @param value
 */
public static void put(String key, Object value){
    data.put(key,value);
    //定時(shí)器 調(diào)度任務(wù)灶平,用于根據(jù) 時(shí)間 定時(shí)清除 對(duì)應(yīng)key 緩存
    executorService.schedule(new TimerTask() {
        @Override
        public void run() {
            remove(key);
        }
    }, DEFAULT_TIMEOUT, TimeUnit.SECONDS);
}

/**
 * 增加緩存  并設(shè)置緩存時(shí)長(zhǎng) 單位 s
 * @param key
 * @param value
 * @param timeout 緩存時(shí)長(zhǎng) 單位s
 */
public static void put(String key, Object value, int timeout){
    data.put(key, value);
    //lambda 替換匿名內(nèi)部類
    executorService.schedule(() -> remove(key), timeout, TimeUnit.SECONDS);
}

獲取緩存

/**
 * 獲取緩存
 * @param key
 * @return
 */
public static Object get(String key){
    return data.get(key);
}

/**
 * 獲取當(dāng)前緩存中 所有的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();
    }
}

測(cè)試方法就不貼了,其他更多相關(guān)方法的實(shí)現(xiàn)箍土,可以看一下GitHub上源碼的具體實(shí)現(xiàn)民逼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市涮帘,隨后出現(xiàn)的幾起案子拼苍,更是在濱河造成了極大的恐慌,老刑警劉巖调缨,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疮鲫,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡弦叶,警方通過查閱死者的電腦和手機(jī)俊犯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伤哺,“玉大人燕侠,你說我怎么就攤上這事×⒗颍” “怎么了绢彤?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蜓耻。 經(jīng)常有香客問我茫舶,道長(zhǎng),這世上最難降的妖魔是什么刹淌? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任饶氏,我火速辦了婚禮讥耗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疹启。我一直安慰自己古程,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布喊崖。 她就那樣靜靜地躺著挣磨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪贷祈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天喝峦,我揣著相機(jī)與錄音势誊,去河邊找鬼。 笑死谣蠢,一個(gè)胖子當(dāng)著我的面吹牛粟耻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播眉踱,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼挤忙,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了谈喳?” 一聲冷哼從身側(cè)響起册烈,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎婿禽,沒想到半個(gè)月后赏僧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扭倾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年淀零,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膛壹。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡驾中,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出模聋,到底是詐尸還是另有隱情肩民,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布链方,位于F島的核電站此改,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏侄柔。R本人自食惡果不足惜共啃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一占调、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧移剪,春花似錦究珊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至攻人,卻和暖如春取试,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背怀吻。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工瞬浓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蓬坡。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓猿棉,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親屑咳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子萨赁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容