概念
LRU(Least Recently Used)是一种淘汰策略,是为了在内存一定的条件下,基于最近最少使用的策略来淘汰元素。Redis的内存淘汰策略中就使用到了LRU。
实现
方法1:通过LinkedHashMap实现
核心点:
1.创建LinkedHashMap时,第三个参数accessOrder必须为true,为true时是基于访问排序,false时是基于插入排序,此时变成了FIFO
2.重写removeEldestEntry方法,当map大小超过容量时返回true,删除最旧的元素
public class LruLinkedHashMap<K, V> {
private int size;
private float factor;
private LinkedHashMap<K, V> linkedHashMap;
public LruLinkedHashMap(int size, float factor) {
this.linkedHashMap = new LinkedHashMap<K, V>(size, factor, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
boolean tooBig = size() > size;
if (tooBig) {
System.out.println("最近最少使用的key=" + eldest.getKey());
}
return tooBig;
}
};
}
public V put(K k, V v) {
return linkedHashMap.put(k, v);
}
public V get(K k) {
return linkedHashMap.get(k);
}
public String toString(){
return linkedHashMap.toString();
}
}
方法2:HashMap+链表实现
核心点:链表的删除、添加等操作的实现细节
public class LruMySelf<K, V> {
private int size;
private Map<K, Node> cache;
private Node head;
private Node tail;
public LruMySelf(int size) {
this.size = size;
this.cache = new HashMap<>();
this.head = null;
this.tail = null;
}
public void put(K key, V value) {
if (cache.containsKey(key)) {
Node node = cache.get(key);
node.value = value;
moveToTail(node);
} else {
Node node = new Node(key, value);
cache.put(key, node);
addToTail(node);
if (cache.size() > size) {
Node oldHead = removeHead();
cache.remove(oldHead.key);
}
}
}
private Node removeHead() {
if (null == head) {
return null;
}
Node node = head;
System.out.println("最近最少使用的key=" + node.key);
if (head == tail) {
head = null;
tail = null;
} else {
head = head.next;
head.pre = null;
}
return node;
}
private void addToTail(Node node) {
if (head == null) {
head = node;
tail = node;
} else {
tail.next = node;
node.pre = tail;
node.next = null;
tail = node;
}
}
private void moveToTail(Node node) {
if (node == null || node == tail) {
return;
}
if (node == head) {
head = head.next;
head.pre = null;
} else {
node.pre.next = node.next;
node.next.pre = node.pre;
}
tail.next = node;
node.pre = tail;
node.next = null;
tail = node;
}
public V get(K key) {
if (cache.containsKey(key)) {
Node node = cache.get(key);
moveToTail(node);
return node.value;
} else {
return null;
}
}
public String toString() {
if (head == null) {
return null;
}
StringBuilder builder = new StringBuilder();
builder.append("{");
Node node = head;
while (node != null) {
builder.append(node.key)
.append("=")
.append(node.value)
.append(",");
node = node.next;
}
return builder.substring(0, builder.length() - 1) + "}";
}
private class Node {
private Node pre;
private Node next;
private K key;
private V value;
public Node(K key, V value) {
this.key = key;
this.value = value;
this.pre = null;
this.next = null;
}
}
}