赞
踩
LRU(Least Recently Used,最近最少使用)算法和
LFU(Least Frequently Used,最不经常使用)算法
都是用来作为缓存淘汰机制,保证缓存空间的有效利用。
适合使用 LRU 的场景:
适合使用 LFU 的场景:
综上,根据访问局部性和热度分布的不同,不同的应用场景会选择不同的缓存淘汰算法,以达到最优的缓存利用效果。
- import java.util.LinkedHashMap;
- import java.util.Map;
-
- public class LRUCache<K, V> extends LinkedHashMap<K, V> {
- private final int MAX_CACHE_SIZE; // 缓存最大容量
-
- public LRUCache(int maxCacheSize) {
- // 第三个参数 accessOrder=true表示按照访问顺序而非插入顺序排序。
- super((int) Math.ceil(maxCacheSize / 0.75) + 1, 0.75f, true);
- MAX_CACHE_SIZE = maxCacheSize;
- }
-
- // 在LRUCache类中,我们通过覆盖removeEldestEntry方法来实现LRU算法的删除策略,当缓存元素长度超过设定的最大容量时,就将最久未使用的元素删除。
- @Override
- protected boolean removeEldestEntry(Map.Entry eldest) {
- return size() > MAX_CACHE_SIZE;
- }
-
- public static void main(String[] args) {
- LRUCache<String, String> cache = new LRUCache<>(3);
- cache.put("1", "one");
- cache.put("2", "two");
- cache.put("3", "three");
- System.out.println(cache);
-
- cache.get("2");
- cache.put("4", "four");
- System.out.println(cache);
-
- cache.put("3", "new-three");
- System.out.println(cache);
- }
- }
输出:
- {1=one, 2=two, 3=three}
- {2=two, 4=four, 3=three}
- {2=two, 4=four, 3=new-three}
- import java.util.HashMap;
- import java.util.LinkedHashSet;
- import java.util.Map;
-
- public class LFUCache {
-
- // 记录key对应的value
- private Map<Integer, Integer> valueMap = new HashMap<>();
- // 记录key键的访问频率
- private Map<Integer, Integer> freqMap = new HashMap<>();
- // 记录每个频率下的key,使用LinkedHashSet保证添加和删除的效率
- private Map<Integer, LinkedHashSet<Integer>> freqKeys = new HashMap<>();
- // LFU缓存容量
- private int capacity;
- // 最小频率
- private int minFreq = 0;
-
- /**
- * LFU缓存构造函数
- * @param capacity 缓存容量
- */
- public LFUCache(int capacity) {
- this.capacity = capacity;
- }
-
- /**
- * 获取LFU缓存中对应key的value值
- * @param key 键
- * @return 对应的值
- */
- public int get(int key) {
- // 如果缓存中没有这个key,返回-1
- if (!valueMap.containsKey(key)) {
- return -1;
- }
- // 更新key的访问频率并返回value值
- int freq = freqMap.get(key);
- freqMap.put(key, freq + 1);
- freqKeys.get(freq).remove(key);
- if (freq == minFreq && freqKeys.get(freq).isEmpty()) {
- // 如果刚刚移除的是最小的频率,更新最小频率
- minFreq++;
- }
- freqKeys.computeIfAbsent(freq + 1, l -> new LinkedHashSet<>()).add(key);
- return valueMap.get(key);
- }
-
- /**
- * 向LFU缓存中添加键值对
- * @param key 键
- * @param value 值
- */
- public void put(int key, int value) {
- if (capacity <= 0) {
- return;
- }
- // 如果缓存中已经有这个key,更新value值
- if (valueMap.containsKey(key)) {
- valueMap.put(key, value);
- get(key);
- return;
- }
- // 缓存已满,移除访问频率最低的key
- if (valueMap.size() >= capacity) {
- int toRemove = freqKeys.get(minFreq).iterator().next();
- freqKeys.get(minFreq).remove(toRemove);
- valueMap.remove(toRemove);
- freqMap.remove(toRemove);
- }
- // 添加新的键值对
- valueMap.put(key, value);
- freqMap.put(key, 1);
- freqKeys.computeIfAbsent(1, l -> new LinkedHashSet<>()).add(key);
- minFreq = 1;
- }
-
- /**
- * 测试用例
- * @param args 参数
- */
- public static void main(String[] args) {
- LFUCache cache = new LFUCache(3);
- cache.put(1, 1);
- cache.put(2, 2);
- System.out.println(cache.get(1)); // 1
- cache.put(3, 3);
- System.out.println(cache.get(2)); // -1
- System.out.println(cache.get(3)); // 3
- cache.put(4, 4);
- System.out.println(cache.get(1)); // -1
- System.out.println(cache.get(3)); // 3
- System.out.println(cache.get(4)); // 4
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。