> ### 数据结构
* 采用 **`HashMap`** 和 **双向链表**的数据结构
* 双向链表中的`Node`保存了缓存的`key`和`value`
* `HashMap<key, Node>`,即`value`为双向链表中的节点
* 每访问一个元素将双向链表中的该元素先删除,再添加到头结点,即将最新访问的节点移到头
* 当缓存满,删除链表尾的节点,同时删除map中的key,再将新元素添加到链表头,添加到map
* 用双向链表是为了记录尾节点,当缓存满时删除尾节点
* 第一开始想法是用单向链表,再额外记录一下头尾节点,但这样是不行的,单向链表可以记录头结点,没有办法记录尾节点,当一个尾节点被删除后,只能从头遍历到尾才能继续记录尾节点。
<br/>
<br/>
> ### 如何实现一个高并发下的线程安全的 LRU缓存 ?
<br/>
<br/>
![](https://i.loli.net/2019/03/21/5c92fabc4ff26.png)
<br/>
![](https://i.loli.net/2019/03/21/5c92faef48410.png)
<br/>
<br/>
> ### leetcode146 [LRU缓存机制](https://leetcode-cn.com/problems/lru-cache/)
```
class LRUCache {
Map<Integer, Node> map = new HashMap<>();
TList list = new TList();
int capacity;
static class Node{
int key;
int value;
Node prev;
Node next;
public Node(int key, int value){
this.key = key;
this.value = value;
}
}
//双向链表,记录头尾节点
static class TList{
Node head;
Node tail;
//添加节点到链表头
public void add(Node node){
if(head == null){
head = tail = node;
node.prev = null;
node.next = null;
return;
}
node.next = head;
node.prev = null;
head.prev = node;
head = node;
}
//移除节点
public void remove(Node node){
if(head.key == tail.key){
head = tail = null;
return;
}
if(node.key == head.key){
head = head.next;
head.prev = null;
return;
}
if(node.key == tail.key){
tail = tail.prev;
tail.next = null;
return;
}
node.prev.next = node.next;
node.next.prev = node.prev;
}
//移除尾节点
public Node removeTail(){
Node node = tail;
if(tail.prev == null){
head = tail = null;
return node;
}
tail.prev.next = null;
tail = tail.prev;
return node;
}
}
public LRUCache(int capacity) {
this.capacity = capacity;
}
public int get(int key) {
if(map.containsKey(key)){
Node node = map.get(key);
list.remove(node);
list.add(node);
return node.value;
}else{
return -1;
}
}
public void put(int key, int value) {
Node node = new Node(key, value);
//put key已存在
if(map.containsKey(key)){
Node old = map.get(key);
old.value = value;
list.remove(old);
list.add(old);
return;
}
//判断是否超过容量
if(map.size() == capacity){
node = list.removeTail();
map.remove(node.key);
Node newNode = new Node(key, value);
map.put(key, newNode);
list.add(newNode);
}else{
map.put(key, node);
list.add(node);
}
}
}
```
***
参考:
[LRU原理和Redis实现](https://zhuanlan.zhihu.com/p/34133067)
- asD
- Java
- Java基础
- Java编译器
- 反射
- collection
- IO
- JDK
- HashMap
- ConcurrentHashMap
- LinkedHashMap
- TreeMap
- 阻塞队列
- java语法
- String.format()
- JVM
- JVM内存、对象、类
- JVM GC
- JVM监控
- 多线程
- 基础概念
- volatile
- synchronized
- wait_notify
- join
- lock
- ThreadLocal
- AQS
- 线程池
- Spring
- IOC
- 特性介绍
- getBean()
- creatBean()
- createBeanInstance()
- populateBean()
- AOP
- 基本概念
- Spring处理请求的过程
- 注解
- 微服务
- 服务注册与发现
- etcd
- zk
- 大数据
- Java_spark
- 基础知识
- Thrift
- hdfs
- 计算机网络
- OSI七层模型
- HTTP
- SSL
- 数据库
- Redis
- mysql
- mybatis
- sql
- 容器
- docker
- k8s
- nginx
- tomcat
- 数据结构/算法
- 排序算法
- 快排
- 插入排序
- 归并排序
- 堆排序
- 计算时间复杂度
- leetcode
- LRU缓存
- B/B+ 树
- 跳跃表
- 设计模式
- 单例模式
- 装饰者模式
- 工厂模式
- 运维
- git
- 前端
- thymeleaf
- 其他
- 代码规范
- work_project
- Interview