什么是淘汰策略?
在容器容量一定的情况下,随着元素的慢慢增多,容量终有满的时刻。而淘汰策略
是当容量要满的时候,用来淘汰剔除部分元素从而来腾出容器空间的策略。常用的淘汰策略有FIFO(先进先出)
、 LRU(The Least Recently Used,最近最久未使用算法)
和LFU(Least Frequently Used ,最近最少使用算法)
FIFO
FIFO(先进先出)
的思想是基于队列。如果一个数据是最先进入的,那么可以认为在将来它被访问的可能性很小。空间满的时候,最先进入的数据会被最早置换(淘汰)掉。
实现方式
使用双向链表,将新加的元素放到链表尾部,当元素满的时候,删除在队列首的元素。在java中LinkedHashMap
继承了hashMap
重写了newNode
、afterNodeRemoval
、的afterNodeInsertion
和afterNodeAccess
。在LinkedHashMap
维护了一个双向链表,在添加一个元素的时候,会将元素插入队列尾,这样我们在可以重写LinkedHashmap
的afterNodeInsertion
方法实现FIFO的算法。
LRU
LRU(The Least Recently Used,最近最久未使用算法)
的思想是基于时间,如果一个元素最久没有使用到,那么在将来中使用到的几率也最少,可以将最久未使用的元素从容器中剔除。
实现方式
LRU同样可以使用双向队列,每次访问某个元素的时候,将访问的元素移动到链表尾,此时链表头的元素便是最久没有访问到的元素,如果容量不够便可以移除表头元素。当把LinkedHashMap
里的accessOrder=true
的时候,每次访问map的元素会将元素放到内部维护的链表尾部,从而表头的元素便是最久没有使用到的元素。
LFU
LFU(Least Frequently Used ,最近最少使用算法)
的思想是基于频率,如果一个元素的使用频率最少,那么在将来使用到的情况也最少,如果元素的频率使用相同,那么在比较其访问时间。
实现方式
LFU是根据次数和访问时间来决定置换元素的,所以我们可以使用:
HashMap<K, V>
:来存储键值。
HashMap<K, C>
:用另外一个Map来存储每个键的访问次数。
HashMap<K,LinkedHashSet<K>>
:来存储如果两个元素访问次数一样的K。
在整个过程中,我们需要记录维护一个最小的访问次数min
,当元素容量超出预期,需要置换元素出来的时候,可以从相同次数Map里面以min
为K的所有K值,来判断是否将这些元素都淘汰,还是根据其他的因子(访问时间戳),来筛选出需要淘汰的元素。