Least Recently Used,即最近最少使用,當一個數據最近一段時間沒有被訪問,將來被訪問的機率也很小。當空間被佔滿後,最早淘汰最近最少使用的數據。java
HashMap的存取是無序的,當咱們但願其有序時,就可使用LinkedHashMap。當LinkedHashMap的構造函數的accessOrder參數爲false時,按插入順序存取;當accessOrder爲true時,按訪問順序存取(新插入的元素放在表尾,剛訪問的元素也移動到表尾)。緩存
LinkedHashMap的組成就是一個HashMap+雙端鏈表。app
插入:ide
插入Entry1函數
插入Entry2ui
插入Entry3spa
更新:3d
思路:code
一、使用LinkedHashMap實現LRUorm
public class LRU1<K, V> { private final int MAX_CACHE_SIZE; private final float DEFAULT_LOAD_FACTORY = 0.75f; LinkedHashMap<K, V> map; public LRU1(int cacheSize) { MAX_CACHE_SIZE = cacheSize; int capacity = (int)Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTORY) + 1; /* * 第三個參數設置爲true,表明linkedlist按訪問順序排序,可做爲LRU緩存 * 第三個參數設置爲false,表明按插入順序排序,可做爲FIFO緩存 */ map = new LinkedHashMap<K, V>(capacity, DEFAULT_LOAD_FACTORY, true) { @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > MAX_CACHE_SIZE; } }; } public synchronized void put(K key, V value) { map.put(key, value); } public synchronized V get(K key) { return map.get(key); } public synchronized void remove(K key) { map.remove(key); } public synchronized Set<Map.Entry<K, V>> getAll() { return map.entrySet(); } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); for (Map.Entry<K, V> entry : map.entrySet()) { stringBuilder.append(String.format("%s: %s ", entry.getKey(), entry.getValue())); } return stringBuilder.toString(); } public static void main(String[] args) { LRU1<Integer, Integer> lru1 = new LRU1<>(5); lru1.put(1, 1); lru1.put(2, 2); lru1.put(3, 3); System.out.println(lru1); lru1.get(1); System.out.println(lru1); lru1.put(4, 4); lru1.put(5, 5); lru1.put(6, 6); System.out.println(lru1); } }
結果:
二、用HashMap和鏈表實現:
主要的思想和上述基本一致,每次添加元素或者讀取元素就將元素放置在鏈表的頭,當緩存滿了以後,就能夠將尾結點元素刪除,這樣就實現了LRU緩存。
這種方法中是經過本身編寫代碼移動結點和刪除結點,爲了防止緩存大小超過限制,每次進行put的時候都會進行檢查,若緩存滿了則刪除尾部元素。
public class LRU2<K, V> { private final int MAX_CACHE_SIZE; private Entry<K, V> head; private Entry<K, V> tail; private HashMap<K, Entry<K, V>> cache; public LRU2(int cacheSize) { MAX_CACHE_SIZE = cacheSize; cache = new HashMap<>(); } public void put(K key, V value) { Entry<K, V> entry = getEntry(key); if (entry == null) { if (cache.size() >= MAX_CACHE_SIZE) { cache.remove(tail.key); removeTail(); } entry = new Entry<>(); entry.key = key; entry.value = value; moveToHead(entry); cache.put(key, entry); } else { entry.value = value; moveToHead(entry); } } public V get(K key) { Entry<K, V> entry = getEntry(key); if (entry == null) { return null; } moveToHead(entry); return entry.value; } public void remove(K key) { Entry<K, V> entry = getEntry(key); if (entry != null) { if (entry == head) { Entry<K, V> next = head.next; head.next = null; head = next; head.pre = null; } else if (entry == tail) { Entry<K, V> prev = tail.pre; tail.pre = null; tail = prev; tail.next = null; } else { entry.pre.next = entry.next; entry.next.pre = entry.pre; } cache.remove(key); } } private void removeTail() { if (tail != null) { Entry<K, V> prev = tail.pre; if (prev == null) { head = null; tail = null; } else { tail.pre = null; tail = prev; tail.next = null; } } } private void moveToHead(Entry<K, V> entry) { if (entry == head) { return; } if (entry.pre != null) { entry.pre.next = entry.next; } if (entry.next != null) { entry.next.pre = entry.pre; } if (entry == tail) { Entry<K, V> prev = entry.pre; if (prev != null) { tail.pre = null; tail = prev; tail.next = null; } } if (head == null || tail == null) { head = tail = entry; return; } entry.next = head; head.pre = entry; entry.pre = null; head = entry; } private Entry<K, V> getEntry(K key) { return cache.get(key); } private static class Entry<K, V> { Entry<K, V> pre; Entry<K, V> next; K key; V value; } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); Entry<K, V> entry = head; while (entry != null) { stringBuilder.append(String.format("%s:%s ", entry.key, entry.value)); entry = entry.next; } return stringBuilder.toString(); } public static void main(String[] args) { LRU2<Integer, Integer> lru2 = new LRU2<>(5); lru2.put(1, 1); System.out.println(lru2); lru2.put(2, 2); System.out.println(lru2); lru2.put(3, 3); System.out.println(lru2); lru2.get(1); System.out.println(lru2); lru2.put(4, 4); lru2.put(5, 5); lru2.put(6, 6); System.out.println(lru2); } }
結果: