1. LRU緩存 (Least Recently Used 刪除最近未使用緩存)
在get/put時,將當前結點移到頭部; 那麼尾部自然是最近未使用的key
import java.util.Map; import java.util.WeakHashMap; /** * LRU緩存 (Least Recently Used 刪除最近未使用緩存) */ public class LRUCache<TKey, TValue> { /** * 緩存node結構 (雙向鏈接) * * @param <TKey> 緩存node的key類型 * @param <TValue> 緩存node的value類型 */ private class Node<TKey, TValue> { /** * 雙向鏈接node的前一個結點 */ private Node<TKey, TValue> prev; /** * 雙向鏈接node的後一個結點 */ private Node<TKey, TValue> next; /** * 緩存的key */ private TKey key; /** * 緩存的value */ private TValue value; public Node() { } public Node(TKey key, TValue value) { this.key = key; this.value = value; } @Override public String toString() { return "Node{" + "key=" + key + ", value=" + value + '}'; } } /** * 增加Map來存儲具體緩存項,來實現O(1)訪問 */ private final Map<TKey, Node<TKey, TValue>> cache = new WeakHashMap<>(); /** * 緩存最大數量 */ private final int capacity; /** * 當前緩存數量 */ private int size; /** * 雙向鏈接的header */ private final Node<TKey, TValue> header; /** * 雙向鏈接的tail */ private final Node<TKey, TValue> tail; /** * 獲取緩存 * * @param key 緩存key * @return 緩存value */ public TValue get(final TKey key) { Node<TKey, TValue> node = cache.get(key); if (node == null) { return null; } // 移到header synchronized (cache) { move2Header(node); } return node.value; } /** * 添加數據 * * @param key 緩存key * @param value 緩存value */ public void put(final TKey key, final TValue value) { Node<TKey, TValue> node = cache.get(key); if (node == null) { synchronized (cache) { if (size >= capacity) { //刪除尾部 Node<TKey, TValue> expireNode = removeTail(); cache.remove(expireNode.key); this.size--; } node = insertHeader(key, value); cache.put(key, node); this.size++; } } else { node.value = value; synchronized (cache) { move2Header(node); } } } /** * 移除緩存 * * @param key 緩存key */ public void remove(final TKey key) { Node<TKey, TValue> node = cache.get(key); if (node == null) { return; } synchronized (cache) { remove(node); this.cache.remove(key); this.size--; } } /** * 添加緩存key/value到鏈表的header * * @param key 緩存key * @param value 緩存value */ private Node<TKey, TValue> insertHeader(final TKey key, final TValue value) { Node<TKey, TValue> node = new Node<>(key, value); return insertHeader(node); } /** * 添加緩存node到鏈表的header * * @param node 緩存node * @return 緩存node */ private Node<TKey, TValue> insertHeader(final Node<TKey, TValue> node) { node.prev = this.header; node.next = this.header.next; this.header.next.prev = node; this.header.next = node; return node; } /** * 移動緩存node到header * * @param node 緩存node */ private void move2Header(final Node<TKey, TValue> node) { remove(node); insertHeader(node); } /** * 刪除鏈表尾部 */ private Node<TKey, TValue> removeTail() { Node<TKey, TValue> node = this.tail.prev; remove(node); return node; } /** * 刪除鏈表的node */ private void remove(final Node<TKey, TValue> node) { node.prev.next = node.next; node.next.prev = node.prev; } /** * 添加緩存node到鏈表的tail * * @param key 緩存node的key * @param value 緩存node的value * @return 緩存node */ private Node<TKey, TValue> putTail(final TKey key, final TValue value) { Node<TKey, TValue> node = new Node<>(key, value); return putTail(node); } /** * 添加緩存node到鏈表的tail * * @param node 緩存node * @return 緩存node */ private Node<TKey, TValue> putTail(final Node<TKey, TValue> node) { node.prev = this.tail.prev; node.next = this.tail; this.tail.prev.next = node; this.tail.prev = node; return node; } /** * .ctor * * @param capacity 最大緩存數量 */ public LRUCache(final int capacity) { this.capacity = capacity; this.header = new Node<>(); this.tail = new Node<>(); this.header.next = this.tail; this.header.prev = null; this.tail.prev = this.header; this.tail.next = null; this.size = 0; } @Override public String toString() { Node<TKey, TValue> node = this.header.next; StringBuilder sb = new StringBuilder(); sb.append("(size:"); sb.append(size); sb.append(")"); while (node != this.tail) { sb.append(node.key); sb.append(":"); sb.append(node.value); sb.append(","); node = node.next; } // sb.append(cache.toString()); return sb.toString(); } }
2.測試.
public static void main(String[] argv) { LRUCache<String, String> cache = new LRUCache<>(4); cache.put("key1", "value1"); System.out.println(cache); cache.put("key2", "value2"); System.out.println(cache); cache.put("key3", "value3"); System.out.println(cache); cache.put("key4", "value4"); System.out.println(cache); cache.put("key4", "value44"); System.out.println(cache); cache.put("key5", "value5"); System.out.println(cache); }
輸出:
(size:1)key1:value1, (size:2)key2:value2,key1:value1, (size:3)key3:value3,key2:value2,key1:value1, (size:4)key4:value4,key3:value3,key2:value2,key1:value1, (size:4)key4:value44,key3:value3,key2:value2,key1:value1, (size:4)key5:value5,key4:value44,key3:value3,key2:value2,