歡迎您光臨本站 註冊首頁

Java實現簡單LRU緩存機制的方法

←手機掃碼閱讀     madbeef @ 2020-05-30 , reply:0

一、什麼是 LRU 算法

就是一種緩存淘汰策略。

計算機的緩存容量有限,如果緩存滿了就要刪除一些內容,給新內容騰位置。但問題是,刪除哪些內容呢?我們肯定希望刪掉哪些沒什麼用的緩存,而把有用的數據繼續留在緩存裡,方便之後繼續使用。

LRU是Least Recently Used的縮寫,即最近最少使用,是一種常用的頁面置換算法,選擇最近最久未使用的頁面予以淘汰。

二、LRU的使用

 LRUCache cache = new LRUCache( 2 /* 緩存容量 */ ); cache.put(1, 1); cache.put(2, 2); cache.get(1); // 返回 1 cache.put(3, 3); // 該操作會使得密鑰 2 作廢


第一步:創建一個長度為2的LRUCache

第二步:cache.put(1, 1);放入key=1,value=1的數據

第三步:cache.put(2,2);放入key = 2,value = 2的數據
(因為2剛使用,所有把2移動到前面)

第四步:cache.get(1);獲取key = 1的數據
(因為我們剛使用了1,所以把1移動到前面)

第五步:cache.put(3,3);放入key = 3,value = 3的數據
(因為3剛放進,所以放前面,又因為容量只有2,需要移除原先的1個。只因key = 2是最近最少使用的(key = 1剛get()過),所以移除2。

三、LRU的實現機制

算法:

LRU 緩存機制可以通過哈希表輔以雙向鏈表實現,我們用一個哈希表和一個雙向鏈表維護所有在緩存中的鍵值對。

1)雙向鏈表按照被使用的順序存儲了這些鍵值對,靠近頭部的鍵值對是最近使用的,而靠近尾部的鍵值對是最久未使用的。

2)哈希表即為普通的哈希映射(HashMap),通過緩存數據的鍵映射到其在雙向鏈表中的位置。

一、初始化:

二、cache.put(1,1):

三、cache.put(2,2):

四、cache.get(1):

五、cache.put(3,3):

四、代碼如下

 import java.io.*; import java.util.HashMap; public class test { public static void main(String args[]) throws IOException { LRUCache cache = new LRUCache( 2 /* 緩存容量 */ ); cache.put(1, 1); cache.put(2, 2); cache.get(1); // 返回 1 cache.put(3, 3); // 該操作會使得密鑰 2 作廢 cache.get(2); // 返回 -1 (未找到) cache.put(4, 4); // 該操作會使得密鑰 1 作廢 cache.get(1); // 返回 -1 (未找到) cache.get(3); // 返回 3 cache.get(4); // 返回 4 } } /** * 設計和實現一個 LRU (最近最少使用) 緩存機制。它應該支持以下操作: 獲取數據 get 和 寫入數據 put */ class LRUCache { private HashMapcache = new HashMap();//方便通過key快速定位結點 private int size; private int capacity; private LinkedNode head,tail; class LinkedNode{ int key; int value; LinkedNode pre; LinkedNode next; } public LRUCache(int capacity) { this.size = 0; this.capacity = capacity; head = new LinkedNode(); tail = new LinkedNode(); head.next = tail; tail.pre = head; } /** * 移除節點 * @param node */ private void removeNode(LinkedNode node) { LinkedNode preNode = node.pre; LinkedNode nextNode = node.next; preNode.next = nextNode; nextNode.pre = preNode; } /** * 添加節點到頭部 * @param node */ private void addNode(LinkedNode node) { node.pre = head; node.next = head.next; head.next.pre = node; head.next = node; } /** * 將節點移動到頭部 * @param node */ private void moveToHead(LinkedNode node) { removeNode(node); addNode(node); } /** * 獲取數據 * @param key * @return */ public int get(int key) { LinkedNode node = cache.get(key); if(node != null) { moveToHead(node); }else{ return -1; } return node.value; } /** * 寫入數據 * @param key * @param value */ public void put(int key, int value) { LinkedNode node = cache.get(key); //存在 if(node != null) { node.value = value;//可能更新數據 moveToHead(node); } //不存在 else{ LinkedNode newNode = new LinkedNode(); newNode.key = key; newNode.value = value; cache.put(key,newNode);//更新Map addNode(newNode);//添加結點到頭部 size++;//更新結點數 if(size > capacity) {//如果結點數超過容量大小 LinkedNode tailPre = tail.pre; cache.remove(tailPre.key);//更新Map removeNode(tailPre);//刪除最後一個結點(尾結點的前一個結點) size--; } } } }


總結:自己實現的簡單LRU總歸太簡單了,要是想完善或者實現更真實的LRU,不妨參考一下Redis中的LRU。(◔◡◔)


[madbeef ] Java實現簡單LRU緩存機制的方法已經有222次圍觀

http://coctec.com/docs/java/show-post-236273.html