Java實現(xiàn)簡單LRU緩存機制的方法
一、什么是 LRU 算法
就是一種緩存淘汰策略。
計算機的緩存容量有限,如果緩存滿了就要刪除一些內容,給新內容騰位置。但問題是,刪除哪些內容呢?我們肯定希望刪掉哪些沒什么用的緩存,而把有用的數(shù)據(jù)繼續(xù)留在緩存里,方便之后繼續(xù)使用。
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 作廢
第一步:創(chuàng)建一個長度為2的LRUCache

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

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

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

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

三、LRU的實現(xiàn)機制
算法:
LRU 緩存機制可以通過哈希表輔以雙向鏈表實現(xiàn),我們用一個哈希表和一個雙向鏈表維護所有在緩存中的鍵值對。
1)雙向鏈表按照被使用的順序存儲了這些鍵值對,靠近頭部的鍵值對是最近使用的,而靠近尾部的鍵值對是最久未使用的。
2)哈希表即為普通的哈希映射(HashMap),通過緩存數(shù)據(jù)的鍵映射到其在雙向鏈表中的位置。
一、初始化:

二、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
}
}
/**
* 設計和實現(xiàn)一個 LRU (最近最少使用) 緩存機制。它應該支持以下操作: 獲取數(shù)據(jù) get 和 寫入數(shù)據(jù) put
*/
class LRUCache {
private HashMap<Integer,LinkedNode> cache = 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;
}
/**
* 移除節(jié)點
* @param node
*/
private void removeNode(LinkedNode node) {
LinkedNode preNode = node.pre;
LinkedNode nextNode = node.next;
preNode.next = nextNode;
nextNode.pre = preNode;
}
/**
* 添加節(jié)點到頭部
* @param node
*/
private void addNode(LinkedNode node) {
node.pre = head;
node.next = head.next;
head.next.pre = node;
head.next = node;
}
/**
* 將節(jié)點移動到頭部
* @param node
*/
private void moveToHead(LinkedNode node) {
removeNode(node);
addNode(node);
}
/**
* 獲取數(shù)據(jù)
* @param key
* @return
*/
public int get(int key) {
LinkedNode node = cache.get(key);
if(node != null) {
moveToHead(node);
}else{
return -1;
}
return node.value;
}
/**
* 寫入數(shù)據(jù)
* @param key
* @param value
*/
public void put(int key, int value) {
LinkedNode node = cache.get(key);
//存在
if(node != null) {
node.value = value;//可能更新數(shù)據(jù)
moveToHead(node);
}
//不存在
else{
LinkedNode newNode = new LinkedNode();
newNode.key = key;
newNode.value = value;
cache.put(key,newNode);//更新Map
addNode(newNode);//添加結點到頭部
size++;//更新結點數(shù)
if(size > capacity) {//如果結點數(shù)超過容量大小
LinkedNode tailPre = tail.pre;
cache.remove(tailPre.key);//更新Map
removeNode(tailPre);//刪除最后一個結點(尾結點的前一個結點)
size--;
}
}
}
}
總結:自己實現(xiàn)的簡單LRU總歸太簡單了,要是想完善或者實現(xiàn)更真實的LRU,不妨參考一下Redis中的LRU。(◔◡◔)
到此這篇關于Java實現(xiàn)簡單LRU緩存機制的方法的文章就介紹到這了,更多相關Java LRU緩存內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java中Spring Boot支付寶掃碼支付及支付回調的實現(xiàn)代碼
這篇文章主要介紹了Java中Spring Boot支付寶掃碼支付及支付回調的實現(xiàn)代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02
java不同版本在多線程中使用隨機數(shù)生成器的實現(xiàn)
本文主要介紹了java不同版本在多線程中使用隨機數(shù)生成器的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-04-04
Mybatis使用useGeneratedKeys獲取自增主鍵
這篇文章主要為大家介紹了Mybatis使用useGeneratedKeys獲取自增主鍵示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01

