一文读懂常见的缓存策略

缓存策略介绍缓存是一种用于临时存储数据的技术,旨在提高数据访问速度和性能 。通过将常用的数据存储在缓存中,可以减少对原始数据存储位置的访问次数,从而加快数据的读取速度 。缓存通常用于加速计算机系统、网络和Web应用程序的性能 。
常见的缓存策略包括:

  1. 「FIFO(First In, First Out)」:先进先出,最先进入缓存的数据最先被淘汰 。
  2. 「LRU(Least Recently Used)」:最近最少使用 , 根据数据最近被访问的时间来淘汰缓存中的数据 。
  3. 「LFU(Least Frequently Used)」:最不经常使用,根据数据被访问的频率来淘汰缓存中的数据 。
  4. 「随机替换」:随机选择要淘汰的数据 。
FIFO缓存策略FIFO(First In, First Out)是一种缓存替换策略,它按照数据进入缓存的顺序来进行替换 。当缓存已满并且需要替换新的数据时,FIFO策略会选择最早进入缓存的数据进行替换 。
在FIFO策略中,新数据被加入到缓存的末尾,而替换时会选择缓存中最早进入的数据进行替换 。这种策略简单直观,但可能会导致缓存中的热数据被频繁替换,影响缓存的命中率 。
数学公式表示FIFO缓存替换策略如下:
假设缓存大小为N,缓存中已有n个数据,新数据为x , 则替换时选择的数据为缓存中最早进入的数据 , 即第一个进入缓存的数据 。
FIFO缓存策略实现(JAVA)FIFO缓存适用于以下使用场景:
  • 数据访问模式呈现出明显的时间局部性
  • 缓存数据量较小 , 且缓存空间有限
  • 对于缓存命中率要求不是特别高的场景
在Java中,可以使用LinkedHashMap来实现FIFO缓存策略 。LinkedHashMap继承自HashMap,它保留了插入顺序,因此非常适合用来实现FIFO缓存 。
import java.util.LinkedHashMap;import java.util.Map;public class FIFOCache<K, V> extends LinkedHashMap<K, V> {private int capacity;public FIFOCache(int capacity) {super(capacity, 0.75f, true);this.capacity = capacity;}@Overrideprotected boolean removeEldestEntry(Map.Entry<K, V> eldest) {return size() > capacity;}public static void mAIn(String[] args) {FIFOCache<String, Integer> cache = new FIFOCache<>(3);cache.put("A", 1);cache.put("B", 2);cache.put("C", 3);System.out.println(cache); // 输出:{A=1, B=2, C=3}cache.put("D", 4);System.out.println(cache); // 输出:{B=2, C=3, D=4}}}在上面的示例中,我们创建了一个FIFOCache类,继承自LinkedHashMap,并重写了removeEldestEntry方法来控制缓存的大小和淘汰策略 。
LRU缓存策略LRU(Least Recently Used)缓存策略是一种常见的缓存淘汰策略 , 它根据数据的访问时间来淘汰最近最少使用的数据 。当缓存空间不足时,会淘汰最近最少被访问的数据,以便为新数据腾出空间 。
LRU缓存策略通常通过双向链表和哈希表来实现 。双向链表用于记录数据的访问顺序,哈希表用于快速查找数据在链表中的位置 。当数据被访问时 , 如果数据已经在缓存中,则将其移动到链表头部;如果数据不在缓存中,则将其添加到链表头部 , 并在哈希表中记录其位置 。当需要淘汰数据时,可以直接从链表尾部淘汰最近最少被访问的数据 。
LRU缓存策略的优点是能够有效地利用缓存空间,将最常用的数据保留在缓存中,提高访问速度 。但是实现起来相对复杂,需要维护链表和哈希表的一致性,并且在高并发场景下可能存在性能瓶颈 。
数学公式表示LRU缓存策略的淘汰规则可以用如下的方式表示:
设  为缓存的大?。? 表示第  个数据被访问的时间,则淘汰规则可以表示为:
淘汰规则:
LRU缓存策略实现(Java)LRU缓存适用于需要频繁访问数据的场景,例如:
  • 数据库查询结果的缓存
  • 网络请求的结果缓存
  • 页面内容的缓存
以下是一个简单的Java使用LinkedHashMap来实现LRU缓存:
import java.util.LinkedHashMap;import java.util.Map;public class LRUCache<K, V> extends LinkedHashMap<K, V> {private final int MAX_ENTRIES;public LRUCache(int maxEntries) {super(maxEntries, 0.75f, true);MAX_ENTRIES = maxEntries;}@Overrideprotected boolean removeEldestEntry(Map.Entry<K, V> eldest) {return size() > MAX_ENTRIES;}public static void main(String[] args) {LRUCache<Integer, String> cache = new LRUCache<>(3);cache.put(1, "One");cache.put(2, "Two");cache.put(3, "Three");System.out.println(cache); // 输出: {1=One, 2=Two, 3=Three}cache.put(4, "Four");System.out.println(cache); // 输出: {2=Two, 3=Three, 4=Four}}}


推荐阅读