高并發(fā)基礎:緩存淘汰算法的 FIFO法精、LRU多律、LFU 詳解

緩存淘汰算法

在高并發(fā)痴突、高性能的質量要求不斷提高時,我們首先會想到的就是利用緩存予以應對菱涤。

第一次請求時把計算好的結果存放在緩存中苞也,下次遇到同樣的請求時洛勉,把之前保存在緩存中的數(shù)據(jù)直接拿來使用粘秆。

但是,緩存的空間一般都是有限收毫,不可能把所有的結果全部保存下來攻走。那么,當緩存空間全部被占滿再有新的數(shù)據(jù)需要被保存此再,就要決定刪除原來的哪些數(shù)據(jù)昔搂。如何做這樣決定需要使用緩存淘汰算法。

常用的緩存淘汰算法有:FIFO输拇、LRU摘符、LFU,下面我們就逐一介紹一下策吠。

FIFO

FIFO逛裤,First In First Out,先進先出算法猴抹。判斷被存儲的時間带族,離目前最遠的數(shù)據(jù)優(yōu)先被淘汰。簡單地說蟀给,先存入緩存的數(shù)據(jù)蝙砌,先被淘汰。

最早存入緩存的數(shù)據(jù)跋理,其不再被使用的可能性比剛存入緩存的可能性大择克。建立一個FIFO隊列,記錄所有在緩存中的數(shù)據(jù)前普。當一條數(shù)據(jù)被存入緩存時肚邢,就把它插在隊尾上。需要被淘汰的數(shù)據(jù)一直在隊列頭汁政。這種算法只是在按線性順序訪問數(shù)據(jù)時才是理想的道偷,否則效率不高。因為那些常被訪問的數(shù)據(jù)记劈,往往在緩存中也停留得最久勺鸦,結果它們卻因變“老”而不得不被淘汰出去。

FIFO 算法用隊列實現(xiàn)就可以了目木,這里就不做代碼實現(xiàn)了换途。

LRU

LRU懊渡,Least Recently Used,最近最少使用算法军拟。判斷最近被使用的時間剃执,目前最遠的數(shù)據(jù)優(yōu)先被淘汰。簡單地說懈息,LRU 的淘汰規(guī)則是基于訪問時間肾档。

如果一個數(shù)據(jù)在最近一段時間沒有被使用到,那么可以認為在將來它被使用的可能性也很小辫继。因此怒见,當緩存空間滿時,最久沒有使用的數(shù)據(jù)最先被淘汰姑宽。

在Java中遣耍,其實LinkedHashMap已經(jīng)實現(xiàn)了LRU緩存淘汰算法,需要在構造函數(shù)第三個參數(shù)傳入true炮车,表示按照時間順序訪問舵变。可以直接繼承LinkedHashMap來實現(xiàn)瘦穆。

package one.more;

import java.util.LinkedHashMap;
import java.util.Map;

public class LruCache<K, V> extends LinkedHashMap<K, V> {

    /**
     * 容量限制
     */
    private int capacity;

    LruCache(int capacity) {
        // 初始大小纪隙,0.75是裝載因子,true是表示按照訪問時間排序
        super(capacity, 0.75f, true);
        //緩存最大容量
        this.capacity = capacity;
    }

    /**
     * 重寫removeEldestEntry方法难审,如果緩存滿了瘫拣,則把鏈表頭部第一個節(jié)點和對應的數(shù)據(jù)刪除。
     */
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > capacity;
    }
}

寫一個簡單的程序測試一下:

package one.more;

public class TestApp {

    public static void main(String[] args) {
        LruCache<String, String> cache = new LruCache(3);
        cache.put("keyA", "valueA");
        System.out.println("put keyA");
        System.out.println(cache);
        System.out.println("=========================");

        cache.put("keyB", "valueB");
        System.out.println("put keyB");
        System.out.println(cache);
        System.out.println("=========================");

        cache.put("keyC", "valueC");
        System.out.println("put keyC");
        System.out.println(cache);
        System.out.println("=========================");

        cache.get("keyA");
        System.out.println("get keyA");
        System.out.println(cache);
        System.out.println("=========================");

        cache.put("keyD", "valueD");
        System.out.println("put keyD");
        System.out.println(cache);
    }
}

運行結果如下:

put keyA
{keyA=valueA}
=========================
put keyB
{keyA=valueA, keyB=valueB}
=========================
put keyC
{keyA=valueA, keyB=valueB, keyC=valueC}
=========================
get keyA
{keyB=valueB, keyC=valueC, keyA=valueA}
=========================
put keyD
{keyC=valueC, keyA=valueA, keyD=valueD}

當然告喊,這個不是面試官想要的麸拄,也不是我們想要的。我們可以使用雙向鏈表和哈希表進行實現(xiàn)黔姜,哈希表用于存儲對應的數(shù)據(jù)拢切,雙向鏈表用于數(shù)據(jù)被使用的時間先后順序。

在訪問數(shù)據(jù)時秆吵,如果數(shù)據(jù)已存在緩存中淮椰,則把該數(shù)據(jù)的對應節(jié)點移到鏈表尾部。如此操作纳寂,在鏈表頭部的節(jié)點則是最近最少使用的數(shù)據(jù)主穗。

當需要添加新的數(shù)據(jù)到緩存時,如果該數(shù)據(jù)已存在緩存中毙芜,則把該數(shù)據(jù)對應的節(jié)點移到鏈表尾部忽媒;如果不存在,則新建一個對應的節(jié)點腋粥,放到鏈表尾部晦雨;如果緩存滿了架曹,則把鏈表頭部第一個節(jié)點和對應的數(shù)據(jù)刪除。

還有 72% 的精彩內容
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
支付 ¥3.99 繼續(xù)閱讀
  • 序言:七十年代末闹瞧,一起剝皮案震驚了整個濱河市绑雄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奥邮,老刑警劉巖万牺,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異漠烧,居然都是意外死亡杏愤,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門已脓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人通殃,你說我怎么就攤上這事度液。” “怎么了画舌?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵堕担,是天一觀的道長。 經(jīng)常有香客問我曲聂,道長霹购,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任朋腋,我火速辦了婚禮齐疙,結果婚禮上,老公的妹妹穿的比我還像新娘旭咽。我一直安慰自己贞奋,他們只是感情好,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布穷绵。 她就那樣靜靜地躺著轿塔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仲墨。 梳的紋絲不亂的頭發(fā)上勾缭,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音目养,去河邊找鬼俩由。 笑死,一個胖子當著我的面吹牛混稽,可吹牛的內容都是我干的采驻。 我是一名探鬼主播审胚,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼礼旅!你這毒婦竟也來了膳叨?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤痘系,失蹤者是張志新(化名)和其女友劉穎菲嘴,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汰翠,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡龄坪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了复唤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片健田。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖佛纫,靈堂內的尸體忽然破棺而出妓局,到底是詐尸還是另有隱情,我是刑警寧澤呈宇,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布好爬,位于F島的核電站,受9級特大地震影響甥啄,放射性物質發(fā)生泄漏存炮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一蜈漓、第九天 我趴在偏房一處隱蔽的房頂上張望穆桂。 院中可真熱鬧,春花似錦迎变、人聲如沸充尉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驼侠。三九已至,卻和暖如春谆吴,著一層夾襖步出監(jiān)牢的瞬間倒源,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工句狼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留笋熬,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓腻菇,卻偏偏與公主長得像胳螟,于是被迫代替她去往敵國和親昔馋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內容