LRUCache简介
没错,面试的时候让我写LRUCache,当时只知道需要一个HashMap和一个链表,但是考虑的问题不全名,也没有考虑到多线程的问题。回来以后学习了下LRUCache的一些Java实现,其实可以套用LinkedHashMap,很多方法都给实现好了,当然也可以使用HashMap+链表,但是后者写起来更加复杂,当时面试的情况,感觉是让我利用LinkedHashMap数据结构。
- 首先缓存的大小是固定的,给缓存分配一个固定的大小。
- 每次读取缓存都会改变缓存的使用时间,将缓存的存在时间重新刷新。
需要在缓存满了后,将最近最久未使用的缓存删除,再添加最新的缓存。
熟悉LinkedHashMap的话可以继承LinkedHashMap来实现LRU缓存。因此需要去查看LinkedHashMap的源码。顺手写了一篇LinkedHashMap源码剖析,写的不是很深刻,不过可以了解其大概的实现方案。
LinkedHashMap实现LRUCache
LinkedHashMap自身实现了顺序存储,通过其初始化参数accessOrder可以指定其顺序方式,accessOrder为false时,采用默认的存储顺序,按照插入顺序存储,也就是一个FIFO缓冲实现,因为最老的总在最前面。而accessOrder为true时,采用的是访问顺序存储,也就是最近读取的数据放在最前面,最早读取的数据放在最后面。同时还有一个判断是否删除最老数据的方法,默认返回false,而我们需要当前缓存的长度小于链表长度时删除链表头的元素。
|
|
运行结果:
|
|
- 继承实现方式,由于继承了Map接口,在多线程环境中使用时可以使用Collections.synchronizedMap()方法来实现线程安全操作。
LinkedHashMap的委托实现
不采用继承,而是采用委托的机制,需要自己进行线程同步来适应多线程场景。
|
|
运行结果
|
|
LRU Cache的链表+HashMap实现
该方法可以理解为手动实现一个LinkedHashMap,同时需要自己处理所线程的问题。
|
|
运行结果:
|
|
继承LinkedHashMap实现FIFO缓存
FIFO缓存只需要继承LinkedHashMap采用其默认的输出顺序就可以。
|
|
输出结果:
|
|