如何实现一个线程安全的LRU

LRU是什么

LRU的中文名字为最近最少使用缓存,一言以蔽之,当加入元素超过存储容量的时候会剔除最少使用过的元素。并且需要get()操作的时间复杂度为O(1)。

LRU有什么作用

LRU在某种程度上可以作为一种淘汰策略使用,比如redis的淘汰策略中就有LRU的淘汰方式。

LRU的非线程安全实现(借助一个数据结构)

通过上述描述可以知道,我们需要两种基本的数据结构,哈希表(用于get和put操作以及在O(1)时间复杂度下实现查询操作)和双向链表(可以设计为链表尾部加入最近访问的元素,链表头部剔除最近未被访问的元素) 。

在Java中同时支持哈希表和双向链表的数据结构为LinkedHashMap, 并且LinkedHashMap可以记录下键插入的顺序, 那么问题可以等价于每一次操作(不管是get还是put), 把原先的键删除,然后都把对应的键插入到链表尾部。
当操作过后超过哈希表的容量的时候,将链表头部的键值对删除即可。

class LRUCache {

    //LRU的实现需要用到的数据结构为哈希表和双向链表
    //在Java中可以同时支持哈希表和双向链表的数据结构为LinkedHashMap
    //LinkedHashMap可以保证插入键按照时间的先后顺序, 所以每一次操作(get/put)都重新插入
    //如果put操作超过LRU的容量,则将双向链表的头部元素移除

    //但是这种LRU无法保证线程安全

    private Map<Integer, Integer> map;
    private int capacity;

    public LRUCache(int capacity) {
        map = new LinkedHashMap<>();
        this.capacity = capacity;
    }
    
    public int get(int key) {
        if (!map.containsKey(key)) {
            return -1;
        }
        Integer val = map.get(key);
        map.remove(key);
        map.put(key, val);
        return val;
    }
    
    public void put(int key, int value) {
        //1. key存在map中, 操作方式同get
        //2. key不存在map中, 新增键值对, 如果超出容量,删除老键值对
        if (map.containsKey(key)) {
            map.remove(key);
            map.put(key, value);
            return;
        }
        map.put(key, value);
        if (map.size() > capacity) {
            map.remove(map.entrySet().iterator().next().getKey());
        }
    }
}

LRU的非线程安全实现(借助哈希表+双端队列)

哈希表用于快速检索到元素, 双端队列队尾用于加上最新处理元素的key, 队头存放最久未处理的元素.

class LRUCache {
   

    //HashMap + ArrayDeque(双端队列)实现
    private int capacity;
    private Map<Integer, Integer> map;
    private Queue<Integer> keyQue;

    public LRUCache(int capacity) {
   
        this.capacity = capacity;
        map = new HashMap<>();
        keyQue = new ArrayDeque<>(
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值