实现一个线程安全并且可以设置过期时间的LRU(LinkedHashMap原理)

本文介绍了LRU缓存的原理,重点讲解了如何使用LinkedHashMap实现线程安全且带有过期时间的LRU缓存。通过设置accessOrder为true实现访问顺序存储,利用removeEldestEntry方法处理缓存淘汰,同时通过ReentrantLock解决并发问题,并使用ScheduledThreadPoolExecutor进行定期删除过期缓存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1、HashMap原理

2、LinkedHashMap实现LRU原理(accessOrder = true)

2.1 数据结构

2.2 put方法

2.3 get方法

2.4 remove方法

3、普通LRU代码实现

4、实现一个线程安全并且可以设置过期时间的LRU缓存

4.1 解决安全问题

4.2 实现定期删除


FIFO的思想是实现一个先进先出的队列,LRU最近最久未使用。可以用双向链表linkedList来实现,同时为了兼顾查询节点时的效率,结合HashMap来实现。双向链表linkedList+HashMap的数据结构可以联想到LinkedHashMap,就不需要我们自己来实现了。LinkedHashMap存储数据是有序的,可以分为插入顺序(accessOrder = false)和访问顺序(accessOrder = true),默认为插入顺序,而且LinkedHashMap提供了删除最后一个节点的方法removeEldestEntry(Map.Entry eldest),正好可以用来实现FIFO(LinkedHashMap按插入顺序存储数据)和LRU算法(LinkedHashMap按访问顺序存储数据)。

1、HashMap原理

底层是Entry数组+链表(Entry节点的next指针)+红黑树。JDK8中,链表长度不小于8时,将链表转化为红黑树。默认无参构造函数会初始化大小为16,向集合中添加元素至集合大小的0.75倍时,会生成一个大小为原来2倍的新集合,然后重新计算元素的地址,将集合中元素插入到新集合,届时效率很低。线程不安全。(例如:put的时候导致的数据覆盖、集合扩展时(resize方法)会出现死循环)。

//HashMap的Entry结构:
static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        int hash;
}

2、LinkedHashMap实现LRU原理(accessOrder = true

  • 2.1 数据结构

HashMap的原理是内部维护了一个Entry数组,而LinkedHashMap在HashMap的基础上,增加了链表头节点和尾节点两个指针,增加了排序方式的标志,Entry节点增加了前后两个指针。因此LinkedHashMap的Entry节点有三个指针,一个是双向链表的前指针、一个是双向链表的后指针、一个是HashMap的hash地址重复时拉链法解决冲突的next的指针。

/*LinkedHashMap的Entry结构:*/
//双向链表头结点
transient LinkedHashMap.Entry<K,V> head;
//双向链表尾节点
transient LinkedHashMap.Entry<K,V> tail;
//是否基于访问顺序排序(默认为false即插入顺序排序)
final boolean accessOrder;
//Entry继承了HashMap的Entry,又增加了before, after两个指针
private static class Entry<K,V> extends HashMap.Entry<K,V> {
        Entry<K,V> before, after;
        Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
            super(hash, key, value, next);
        }
}
  • 2.2 put方法

如果put的是新key,则将Entry节点添加到Map中,并添加到双向链表的尾部,若initialCapacity数量已满,删除最近最久未使用的Entry节点即双向链表的头结点;若put的是已有的key,更新节点的value,并将节点删除并添加到尾部。

HashMap的put方法会生成一个节点,调用了newNode方法,而LinkedHashMap重写了此方法
 /**
     * 创建一个节点
     * @param hash  hash值
     * @param key   键
     * @param value 值
     * @param e     下一个节点,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值