成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

緩存淘汰策略指南:程序員必懂的四種方法

存儲 存儲架構
掌握這些策略的組合拳,才能真正讓緩存成為系統性能的加速器。下次設計緩存模塊時,不妨先畫個業務場景象限圖,找到最適合的淘汰策略組合。

緩存就像快遞站里的臨時貨架:把最常用的包裹放在最顯眼的位置,下次取件時就能省下翻倉庫的時間。但貨架空間有限,到底該淘汰哪些包裹?今天用真實場景拆解程序員必懂的四種緩存淘汰策略。

排隊淘汰法(FIFO)—先來后到的公平策略

原理:就像超市儲物柜,先存入的包裹會被優先清理。緩存滿時,第一個存入的數據最先被淘汰。

適用場景

? ?? 短視頻APP的本地草稿箱(用戶一般處理最新草稿)

? ?? 訂單系統的臨時流水號生成(舊流水號過期即失效)

避坑指南:當熱門商品(如秒殺活動的爆款)被頻繁訪問時,可能剛存入就被后續數據擠出緩存,導致緩存命中率暴跌。

Java示例

// 使用LinkedHashMap的天然隊列特性
public class FIFOCache<K,V> extends LinkedHashMap<K,V> {
    private final int maxSize;
    
    public FIFOCache(int maxSize) {
        super(maxSize, 0.75f, false); // true改為false關閉訪問排序
        this.maxSize = maxSize;
    }

    @Override
    protected boolean removeEldestEntry(Entry<K,V> eldest) {
        return size() > maxSize;
    }
}

// 測試:存入4個元素,觀察最早元素被淘汰
FIFOCache<String, Product> cache = new FIFOCache<>(3);
cache.put("P1001", new Product("iPhone15"));
cache.put("P1002", new Product("小米充電寶"));
cache.put("P1003", new Product("華為耳機"));
cache.put("P1004", new Product("OPPO手表")); 
// 此時緩存中只剩P1002/P1003/P1004

熱點守護者(LRU)—讓緩存記住你的喜好

原理:給每個數據貼「最后訪問時間」標簽,就像瀏覽器歷史記錄,長期不看的頁面會被自動清理。

真實案例

?  微信朋友圈緩存(最近瀏覽的朋友動態優先保留)

? 電商商品詳情頁緩存(用戶反復查看的商品常駐內存)

性能陷阱:直接使用LinkedHashMap的默認實現,在千萬級并發時鏈表調整可能導致性能瓶頸。生產環境建議結合ConcurrentHashMap改造。

Java示例

public class ConcurrentLRU<K,V> {

    private final ConcurrentHashMap<K,V> map = new ConcurrentHashMap<>();
    private final ConcurrentLinkedDeque<K> queue = new ConcurrentLinkedDeque<>();
    private final int maxSize;

    public void put(K key, V value) {
        if (map.size() >= maxSize) {
            KoldestKey= queue.poll();  // 并發安全的隊列操作
            map.remove(oldestKey);
        }
        queue.addLast(key);
        map.put(key, value);
    }

    public V get(K key) {
        queue.remove(key);     // 先刪除舊位置
        queue.addLast(key);    // 插入隊列尾部表示最近使用
        return map.get(key);
    }
}

高頻VIP室(LFU)—只為真愛粉保留座位

原理:統計每個數據的訪問次數,像機場貴賓廳,只允許最頻繁出行的旅客進入。

適用場景

  • ? 新聞APP的熱搜榜單緩存(統計點擊量)
  • ? 音樂平臺的排行榜數據(按播放次數排序)

致命缺陷:早期的《哈利波特》小說訪問100次后不再打開,會長期霸占緩存空間,而新上架的《三體》可能因初始訪問量低無法進入緩存。

優化方案:引入訪問次數衰減機制:每隔1小時將所有計數器減半,讓新熱點有機會進入緩存。

Java示例

import java.util.*;

public class LFUCache<K, V> {
    private final int capacity;
    // 核心存儲結構:key -> 值和頻率
    private final HashMap<K, ValueWrapper> cache;
    // 頻率 -> 相同頻率的key集合(使用LinkedHashSet保持插入順序)
    private final HashMap<Integer, LinkedHashSet<K>> freqMap;
    private int minFrequency;

    public LFUCache(int capacity) {
        this.capacity = capacity;
        this.cache = new HashMap<>();
        this.freqMap = new HashMap<>();
        this.minFrequency = 0;
    }

    public V get(K key) {
        ValueWrapper wrapper= cache.get(key);
        if (wrapper == null) return null;
        
        // 更新頻率
        updateFrequency(key, wrapper);
        return wrapper.value;
    }

    public void put(K key, V value) {
        if (capacity <= 0) return;
        
        if (cache.containsKey(key)) {
            // 已存在則更新值和頻率
            ValueWrapper wrapper= cache.get(key);
            wrapper.value = value;
            updateFrequency(key, wrapper);
        } else {
            // 新增元素時的淘汰邏輯
            if (cache.size() >= capacity) {
                evict();
            }
            cache.put(key, new ValueWrapper(value, 1));
            freqMap.computeIfAbsent(1, k -> new LinkedHashSet<>()).add(key);
            minFrequency = 1;
        }
    }

    // 更新頻率的核心方法
    private void updateFrequency(K key, ValueWrapper wrapper) {
        int oldFreq= wrapper.frequency;
        wrapper.frequency++;
        
        // 從舊頻率集合移除
        freqMap.get(oldFreq).remove(key);
        if (freqMap.get(oldFreq).isEmpty()) {
            freqMap.remove(oldFreq);
            if (minFrequency == oldFreq) minFrequency++;
        }
        
        // 加入新頻率集合
        freqMap.computeIfAbsent(wrapper.frequency, k -> new LinkedHashSet<>()).add(key);
    }

    // 執行淘汰操作
    private void evict() {
        LinkedHashSet<K> keys = freqMap.get(minFrequency);
        K evictKey= keys.iterator().next();
        keys.remove(evictKey);
        if (keys.isEmpty()) {
            freqMap.remove(minFrequency);
        }
        cache.remove(evictKey);
    }

    // 測試用例
    public static void main(String[] args) {
        LFUCache<String, Integer> cache = new LFUCache<>(2);
        cache.put("A", 1);
        cache.put("B", 2);
        cache.get("A"); // 訪問A使頻率變為2
        cache.put("C", 3); // 淘汰B(A頻率2,B頻率1)
        System.out.println(cache.get("B")); // 輸出null
    }

    // 內部值包裝類
    private class ValueWrapper {
        V value;
        int frequency;

        ValueWrapper(V value, int frequency) {
            this.value = value;
            this.frequency = frequency;
        }
    }
}

抽獎式淘汰(Random)—簡單粗暴的生存游戲

原理:隨機選擇犧牲品,像吃雞游戲的毒圈,存活全靠運氣。

使用場景

? 臨時驗證碼緩存(無論是否使用,5分鐘后強制過期)

? A/B測試時的臨時實驗數據存儲

Java示例

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;

public class RandomCache<K, V> {
    private final Map<K, V> cache = new ConcurrentHashMap<>();
    private final List<K> keyList = new ArrayList<>();
    private final Object lock=new Object();

    public void put(K key, V value) {
        synchronized (lock) {
            if (!cache.containsKey(key)) {
                keyList.add(key);
            }
            cache.put(key, value);
        }
    }

    public V get(K key) {
        return cache.get(key);
    }

    public void evict() {
        synchronized (lock) {
            if (!keyList.isEmpty()) {
                int randomIndex= ThreadLocalRandom.current().nextInt(keyList.size());
                K evictKey= keyList.get(randomIndex);
                
                // 將待刪除元素與最后一個元素交換后刪除
                int lastIndex= keyList.size() - 1;
                K lastKey= keyList.get(lastIndex);
                keyList.set(randomIndex, lastKey);
                keyList.remove(lastIndex);
                
                cache.remove(evictKey);
            }
        }
    }

    // 測試用例
    public static void main(String[] args) {
        RandomCache<String, Integer> cache = new RandomCache<>();
        cache.put("X", 10);
        cache.put("Y", 20);
        cache.evict();
        System.out.println(cache.get("X")); // 50%概率輸出null
    }
}

進階技巧

混合策略:例如短視頻采用LRU+FIFO組合,新視頻先進入FIFO隊列,達到一定訪問量后晉升到LRU池

分級緩存:Redis+L1/L2緩存設計,熱點數據用LRU,長尾數據用LFU

動態調整:例如外賣根據時段自動切換策略,午高峰用LFU保商家信息,夜間切Random降內存消耗

掌握這些策略的組合拳,才能真正讓緩存成為系統性能的加速器。下次設計緩存模塊時,不妨先畫個業務場景象限圖,找到最適合的淘汰策略組合。

責任編輯:武曉燕 來源: 沐雨花飛碟
相關推薦

2013-06-28 10:17:04

2020-11-11 11:25:27

Redis數據技術

2023-09-03 17:03:54

工具RegexGPTBloop

2014-05-14 10:13:50

程序員機器學習

2014-03-17 09:22:43

Linux命令

2022-09-02 14:29:01

JavaScrip數組屬性

2017-11-20 22:28:43

程序員源代碼編程

2009-11-23 15:57:51

PHP偽靜態

2021-03-10 10:13:39

爬蟲Python代碼

2022-07-04 07:09:55

架構

2011-06-22 15:21:08

XML

2009-02-25 09:52:14

類型轉換.NET 強制轉型

2020-08-10 00:30:55

備份密碼iPhone移動安全

2009-03-31 13:12:30

解析XMLJava

2015-11-06 13:27:39

2022-12-07 10:28:22

2022-11-04 13:35:29

IT遠程工作混合工作

2016-06-28 10:19:31

云計算云安全

2010-07-16 13:50:53

Perl哈希表

2010-03-18 17:57:37

Java XMLSoc
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲乱码一区二区 | 中文字幕精品一区二区三区精品 | 天天干视频在线 | 日本久久精品视频 | 欧美一极视频 | 日本h片在线观看 | 日日操av| 欧美色综合天天久久综合精品 | 视频一区在线观看 | 久久久久久亚洲国产精品 | 成年网站在线观看 | 日韩靠逼 | 成人午夜免费福利视频 | 国精产品一品二品国精在线观看 | 欧美日韩亚洲二区 | 午夜精品一区二区三区三上悠亚 | 一区二区三区视频在线 | 超碰97在线免费 | 国产日韩精品在线 | 久热免费 | 国产福利视频网站 | 久久国产精品一区二区 | 国产91 在线播放 | 夜夜操天天操 | 日本黄色片免费在线观看 | 亚洲精品久久久久久下一站 | 欧美色综合天天久久综合精品 | 国产精品久久久久久久久久久久久 | 欧美一区二区在线观看 | 成人小视频在线观看 | 亚洲国产视频一区二区 | 黄色网址免费在线观看 | 日韩免费在线观看视频 | 欧美在线免费 | 91精品国产高清一区二区三区 | 亚洲 中文 欧美 日韩 在线观看 | 亚洲精品丝袜日韩 | 欧美色成人 | 欧美一区二区三区在线 | 精品视频免费在线 | 国产情侣在线看 |