Java LocalCache 本地緩存的實(shí)現(xiàn)

源碼地址: GitHub

使用場景

Java應(yīng)用中橘霎,對于訪問頻率高蔫浆,更新少的數(shù)據(jù),通常的方案是將這類數(shù)據(jù)加入緩存中姐叁。相對從數(shù)據(jù)庫中讀取來說瓦盛,讀緩存效率會(huì)有很大提升。

在集群環(huán)境下外潜,常用的分布式緩存有Redis原环、Memcached等。但在某些業(yè)務(wù)場景上处窥,可能不需要去搭建一套復(fù)雜的分布式緩存系統(tǒng)嘱吗,在單機(jī)環(huán)境下,通常是會(huì)希望使用內(nèi)部的緩存(LocalCache)滔驾。

實(shí)現(xiàn)

這里提供了兩種LocalCache的實(shí)現(xiàn)谒麦,一種是基于ConcurrentHashMap實(shí)現(xiàn)基本本地緩存,另外一種是基于LinkedHashMap實(shí)現(xiàn)LRU策略的本地緩存嵌灰。

基于ConcurrentHashMap的實(shí)現(xiàn)

    static {
        timer = new Timer();
        map = new ConcurrentHashMap<>();
    }

ConcurrentHashMap作為緩存的存儲(chǔ)結(jié)構(gòu)弄匕。因?yàn)?code>ConcurrentHashMap的線程安全的,所以基于此實(shí)現(xiàn)的LocalCache在多線程并發(fā)環(huán)境的操作是安全的沽瞭。在JDK1.8中迁匠,ConcurrentHashMap是支持完全并發(fā)讀,這對本地緩存的效率也是一種提升驹溃。通過調(diào)用ConcurrentHashMapmap的操作來實(shí)現(xiàn)對緩存的操作城丧。

私有構(gòu)造函數(shù)
    private LocalCache() {

    }

LocalCache是工具類,通過私有構(gòu)造函數(shù)強(qiáng)化不可實(shí)例化的能力豌鹤。

緩存清除機(jī)制
   /**
     * 清除緩存任務(wù)類
     */
    static class CleanWorkerTask extends TimerTask {

        private String key;

        public CleanWorkerTask(String key) {
            this.key = key;
        }

        public void run() {
            LocalCache.remove(key);
        }
    }

清理失效緩存是由Timer類實(shí)現(xiàn)的亡哄。內(nèi)部類CleanWorkerTask繼承于TimerTask用戶清除緩存。每當(dāng)新增一個(gè)元素的時(shí)候布疙,都會(huì)調(diào)用timer.schedule加載清除緩存的任務(wù)蚊惯。

基于LinkedHashMap的實(shí)現(xiàn)

LinkedHashMap作為緩存的存儲(chǔ)結(jié)構(gòu)愿卸。主要是通過LinkedHashMap的按照訪問順序的特性來實(shí)現(xiàn)LRU策略。

LRU

LRULeast Recently Used的縮寫截型,即最近最久未使用趴荸。LRU緩存將會(huì)利用這個(gè)算法來淘汰緩存中老的數(shù)據(jù)元素,從而優(yōu)化內(nèi)存空間宦焦。

基于LRU策略的map

這里利用LinkedHashMap來實(shí)現(xiàn)基于LRU策略的map发钝。通過調(diào)用父類LinkedHashMap的構(gòu)造函數(shù)來實(shí)例化map。參數(shù)accessOrder設(shè)置為true保證其可以實(shí)現(xiàn)LRU策略波闹。

static class LRUMap<K, V> extends LinkedHashMap<K, V> {

        ...  // 省略部分代碼
        
        public LRUMap(int initialCapacity, float loadFactor) {
            super(initialCapacity, loadFactor, true);
        }

        ... // 省略部分代碼
        
        /**
         * 重寫LinkedHashMap中removeEldestEntry方法;
         * 新增元素的時(shí)候,會(huì)判斷當(dāng)前map大小是否超過DEFAULT_MAX_CAPACITY,超過則移除map中最老的節(jié)點(diǎn);
         *
         * @param eldest
         * @return
         */
        protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
            return size() > DEFAULT_MAX_CAPACITY;
        }

    }
線程安全
        /**
         * 讀寫鎖
         */
        private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

        private final Lock rLock = readWriteLock.readLock();

        private final Lock wLock = readWriteLock.writeLock();

LinkedHashMap并不是線程安全酝豪,如果不加控制的在多線程環(huán)境下使用的話,會(huì)有問題精堕。所以在LRUMap中引入了ReentrantReadWriteLock讀寫鎖孵淘,來控制并發(fā)問題。

緩存淘汰機(jī)制
        protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
            return size() > DEFAULT_MAX_CAPACITY;
        }

此處重寫LinkedHashMapremoveEldestEntry方法锄码, 當(dāng)緩存新增元素的時(shí)候,會(huì)判斷當(dāng)前map大小是否超過DEFAULT_MAX_CAPACITY,超過則移除map中最老的節(jié)點(diǎn)夺英。

緩存清除機(jī)制

緩存清除機(jī)制與ConcurrentHashMap的實(shí)現(xiàn)一致,均是通過timer實(shí)現(xiàn)滋捶。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痛悯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子重窟,更是在濱河造成了極大的恐慌载萌,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巡扇,死亡現(xiàn)場離奇詭異扭仁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)厅翔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門乖坠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人刀闷,你說我怎么就攤上這事熊泵。” “怎么了甸昏?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵顽分,是天一觀的道長。 經(jīng)常有香客問我施蜜,道長卒蘸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任翻默,我火速辦了婚禮缸沃,結(jié)果婚禮上恰起,老公的妹妹穿的比我還像新娘。我一直安慰自己和泌,他們只是感情好村缸,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著武氓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仇箱。 梳的紋絲不亂的頭發(fā)上县恕,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機(jī)與錄音剂桥,去河邊找鬼忠烛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛权逗,可吹牛的內(nèi)容都是我干的美尸。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼斟薇,長吁一口氣:“原來是場噩夢啊……” “哼师坎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起堪滨,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤胯陋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后袱箱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體遏乔,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年发笔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盟萨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡了讨,死狀恐怖捻激,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情量蕊,我是刑警寧澤铺罢,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站残炮,受9級(jí)特大地震影響韭赘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜势就,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一泉瞻、第九天 我趴在偏房一處隱蔽的房頂上張望脉漏。 院中可真熱鬧,春花似錦袖牙、人聲如沸侧巨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽司忱。三九已至,卻和暖如春畴蹭,著一層夾襖步出監(jiān)牢的瞬間坦仍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工叨襟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留繁扎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓糊闽,卻偏偏與公主長得像梳玫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子右犹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評論 2 348

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

  • Java SE 基礎(chǔ): 封裝提澎、繼承、多態(tài) 封裝: 概念:就是把對象的屬性和操作(或服務(wù))結(jié)合為一個(gè)獨(dú)立的整體傀履,并盡...
    Jayden_Cao閱讀 2,103評論 0 8
  • 從三月份找實(shí)習(xí)到現(xiàn)在虱朵,面了一些公司,掛了不少钓账,但最終還是拿到小米碴犬、百度、阿里梆暮、京東服协、新浪、CVTE啦粹、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,207評論 11 349
  • 理論總結(jié) 它要解決什么樣的問題偿荷? 數(shù)據(jù)的訪問、存取唠椭、計(jì)算太慢跳纳、太不穩(wěn)定、太消耗資源贪嫂,同時(shí)寺庄,這樣的操作存在重復(fù)性。因...
    jiangmo閱讀 2,840評論 0 11
  • 下面是我自己收集整理的Java線程相關(guān)的面試題,可以用它來好好準(zhǔn)備面試斗塘。 參考文檔:-《Java核心技術(shù) 卷一》-...
    阿呆變Geek閱讀 14,757評論 14 507