LRU原理:
LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:
1. 新数据插入到链表头部;
2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部;
3. 当链表满的时候,将链表尾部的数据丢弃。
下面是代码实现LRUCache缓存实现,并确保线程安全:
import java.util.concurrent.ConcurrentHashMap;
/**
* @Author: heyongjian
* @Date:2019/3/29
* LRUCache核心思想:末尾淘汰制,即使用最少放置尾部,最近使用放置首尾
* 存储结构采用ConcurrentHashMap实现线程安全读写
* 淘汰机制采用双向链表,插入,修改效率高
*/
public class LRUCache {
//容量大小
private int capacity;
//map存储
private ConcurrentHashMap<Integer,Node> map = new ConcurrentHashMap<>();
//头元素
private Node head = null;
//尾部元素
private Node end = null;
public LRUCache(int capacity) {
this.capacity = capacity;
}
/**
* 如果换成存在改key值,则返回对应value值,并将该节点放置首尾,否则返回-1
* @param key key值
* @return 返回对应的value
*/
public int get(int key){
//如果已经包含
if (map.containsKey(key)){
Node n = map.get(key);//先获取对应的值,赋给节点n
remove(n);//删除原来位置的节点n
setHead(n);//并重新将节点n插入到头部
return n.value;
}
return -1;
}
/**
*如果键值不存在,执行插入操作:如果已达到相应大小,则最近最少使用项无效;
* @param key 键
* @param value 值
*/
private void set(int key,int value){
//如果已经存在
if (map.containsKey(key)){
Node old = map.get(key);
old.value = value;//当前值替换旧值
remove(old);//同样删除
setHead(old);//重新在头部插入
}else {
//不存在,则需要创建新节点
Node created = new Node(key,value);
if (map.size()>=capacity){//插入时,map大小已经超过当前容量
map.remove(end.key);//则移除最少使用的元素
remove(end);//移除最后一个节点
setHead(created);//把当前创建的节点放值首尾
}
map.put(key,created);
}
}
/**
* 将当前节点移至首部
* @param n 当前节点
*/
private synchronized void setHead(Node n){
//将当前的节点的下一个节点指向当前的头节点
n.next = head;
//将当前节点的头节点指向null
n.pre = null;
//如果头节点为null,则将头节点的前一个节点指向当前节点n
if (head!=null)
head.pre = n;
//否则,将当前节点的赋给头节点
head =n;
//如果尾节点为null,则将头节点赋给尾部几点
if (end==null)
end=head;
}
/**
* 删除节点
* @param n 传入节点
*/
private synchronized void remove(Node n){
//如果当前节点的上一个节点不为null,则将当前节点的下一个节点赋给上一个节点的下一个节点,即删除当前节点
if (n.pre!=null) n.pre.next = n.next;
else head = n.next; //如果当前节点的上一个节点为null,则当前节点的下一个节点赋给头节点,即为头节点
if (n.next!=null)//如果当前节点的下一个节点为null,则当前节点的上一个节点赋给当前节点的下一个节点的上一个节点
n.next.pre=n.pre;
//如果当前节点的下一个节点为null,则已是最后一个节点,删除当前节点无需做修改
}
//节点
static class Node{
int key;
int value;
Node pre;
Node next;
Node(int key, int value){
this.key = key;
this.value = value;
}
}
}