LRU最近最少使用算法
一、LRU算法
1.简介
LRU(Least Recently Used,最近最少使用)算法是一种常用的缓存淘汰策略,当缓存达到其容量上限时,它会移除那些最久没有被访问的数据项。这种策略基于这样一个假设:如果一个数据项在近期没有被访问过,那么在未来一段时间内也不太可能被访问。
2.LRU算法的核心思想
LRU算法的核心在于追踪每个数据项的访问历史,并优先保留最近被访问过的数据项。具体来说,每当有新的数据需要存储而缓存已满时,LRU算法会选择移除那个最长时间未被访问的数据项。
二、算法题目
1.LeetCode题目
2.实现
class LRUCache extends LinkedHashMap<Integer, Integer> {
private int capacity;
public LRUCache(int capacity) {
super(capacity, 0.75F, true);
this.capacity = capacity;
}
public int get(int key) {
return getOrDefault(key, -1);
}
public void put(int key, int value) {
super.put(key, value);
}
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
return size() > capacity;
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
三、项目中实现
- 定义Cache接口
package com.zzc.design.cache;
import java.util.concurrent.Callable;
public interface Cache<K, V> {
/**
* 添加值到缓存中,如果key已经存在,值将会被覆盖
* @param key
* @param val
*/
void put(K key, V val);
/**
* 根据key从缓存中获取value
* @param key
* @return
*/
V get(K key);
/**
* “加载-通过”模式(load-through pattern)
* 从缓存中获取值,如果该值不存在,则通过给定的函数处理并将其结果更新到缓存中。
* @param key
* @param call
* @return
* @throws Exception
*/
V get(K key, Callable<? extends V> call) throws Exception;
/**
* 通过key移除缓存
* @param key
* @return
*/
V remove(K key);
/**
* 清除整个缓存
*/
void clear();
/**
* 缓存数量大小
* @return
*/
int getCapacity();
}
- 实现具体存储key-value数据的接口
package com.zzc.design.cache;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
public class SimpleCache<K, V> implements Cache<K, V> {
private final Map<K, V> cache;
public SimpleCache(int size) {
cache = new HashMap<>(size);
}
@Override
public void put(K key, V val) {
cache.put(key, val);
}
@Override
public V get(K key) {
return cache.get(key);
}
@Override
public V get(K key, Callable<? extends V> call) throws Exception {
if (cache.containsKey(key)) {
return cache.get(key);
} else {
V v2 = call.call();
cache.put(key, v2);
return v2;
}
}
@Override
public V remove(K key) {
return cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
@Override
public int getCapacity() {
return cache.size();
}
}
- 拓展LRU缓存类型
package com.zzc.design.cache.lru;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Callable;
public class LruCache<K, V> implements Cache<K, V> {
/**
* 存储键值对数据
*/
private final Cache<K, V> delegate;
/**
* 跟踪键的访问顺序,从而实现 LRU 策略
*/
private Map<K, V> visits;
/**
* 记录最近要被移除的最老键
*/
private K eldestKey;
public LruCache(Cache<K, V> delegate, int capacity) {
this.delegate = delegate;
setCapacity(capacity);
}
public void setCapacity(final int capacity) {
visits = new LinkedHashMap<K, V>(capacity, .75F, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
boolean tooBig = size() > capacity;
if (tooBig) {
eldestKey = eldest.getKey();
}
return tooBig;
}
};
}
@Override
public void put(K key, V val) {
delegate.put(key, val);
cycleKeyList(key);
}
@Override
public V get(K key) {
visits.get(key);
return delegate.get(key);
}
@Override
public V get(K key, Callable<? extends V> call) throws Exception {
return delegate.get(key, call);
}
@Override
public V remove(K key) {
return delegate.remove(key);
}
@Override
public void clear() {
delegate.clear();
visits.clear();
}
@Override
public int getCapacity() {
return delegate.getCapacity();
}
private void cycleKeyList(K key) {
visits.put(key, null);
if (eldestKey != null) {
delegate.remove(eldestKey);
eldestKey = null;
}
}
}
- Demo示例
package com.zzc.design.cache.lru;
import com.zzc.design.cache.Cache;
import com.zzc.design.cache.SimpleCache;
public class Demo {
private static final int initCapacity = 1;
private static final int maxCapacity = 3;
public static void main(String[] args) {
Cache<String, String> cache = new LruCache<>(new SimpleCache<>(initCapacity), maxCapacity);
cache.put("key1", "value1");
cache.put("key2", "value2");
cache.put("key3", "value3");
System.out.println(cache.get("key1"));//访问key1
System.out.println(cache.get("key2"));//访问key2
System.out.println(cache.get("key3"));//访问key3
System.out.println(cache.get("key1"));//访问key1
System.out.println(cache.get("key2"));//访问key2
cache.put("key4", "value4");//新增key4
System.out.println(cache.get("key3"));//key3的访问次数最少,在添加key4的时候被删除掉了
}
}
/*
* 结果:
* value1
* value2
* value3
* value1
* value2
* null
*/