Java 实现 FIFO 缓存算法
Posted 龙凌云端
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 实现 FIFO 缓存算法相关的知识,希望对你有一定的参考价值。
Java 实现 FIFO 缓存算法
一、什么是 FIFO
二、Java 实现 FIFO 算法
1、方案1
import java.util.LinkedList;
public class FIFOQueue<T>
private final LinkedList<T> queue = new LinkedList<T>();
private final int maxSize;
public FIFOQueue(int maxSize)
this.maxSize = maxSize;
public void add(T item)
if (queue.size() >= maxSize)
queue.removeFirst();
queue.addLast(item);
public T remove()
return queue.removeFirst();
public boolean isEmpty()
return queue.isEmpty();
public int size()
return queue.size();
public T peek()
return queue.peek();
public class Test
public static void main(String[] args)
FIFOQueue<String> queue = new FIFOQueue<>(5);
queue.add("a");
queue.add("b");
queue.add("c");
System.out.println(queue.remove()); // 输出:a
System.out.println(queue.peek()); // 输出:b
System.out.println(queue.size()); // 输出:2
queue.add("d");
queue.add("e");
queue.add("f");
System.out.println(queue.remove()); // 输出:b
2、方案2
import java.util.LinkedList;
public class FIFOCache<K, V>
private final int capacity;
private final LinkedList<K> keyList;
private final Map<K, V> cacheMap;
public FIFOCache(int capacity)
this.capacity = capacity;
this.keyList = new LinkedList<>();
this.cacheMap = new HashMap<>();
public synchronized void put(K key, V value)
if (keyList.size() == capacity)
K removedKey = keyList.removeFirst();
cacheMap.remove(removedKey);
keyList.addLast(key);
cacheMap.put(key, value);
public synchronized V get(K key)
return cacheMap.get(key);
详解三种缓存过期策略LFU,FIFO,LRU(附带实现代码)
在学操作系统的时候,就会接触到缓存调度算法,缓存页面调度算法:先分配一定的页面空间,使用页面的时候首先去查询空间是否有该页面的缓存,如果有的话直接拿出来,如果没有的话先查询,如果页面空间没有满的时候,使用新页面的时候,就释放旧的页面空间,把新页面缓存起来,以便下次使用同样的页面的时候方便调用。
缓存调度流程图
缓存机制就是上面所说的那样,但是实现的过程以及淘汰旧页面的机制不同,所以会有不同缓存调度方法,就常见的就是FIFO,LRU,LFU缓存过期策略。
1.FIFO(First In First out):先见先出,淘汰最先近来的页面,新进来的页面最迟被淘汰,完全符合队列。
2.LRU(Least recently used):最近最少使用,淘汰最近不使用的页面
3.LFU(Least frequently used): 最近使用次数最少, 淘汰使用次数最少的页面
下面详细解释三种算法是怎么实现的。下面解释转自http://blog.csdn.net/yangpl_tale/article/details/44998423
一、FIFO
按照“先进先出(First In,First Out)”的原理淘汰数据,正好符合队列的特性,数据结构上使用队列Queue来实现。
如下图:
1. 新访问的数据插入FIFO队列尾部,数据在FIFO队列中顺序移动;
2. 淘汰FIFO队列头部的数据;
二、LRU
(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:
1. 新数据插入到链表头部;
2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部;
3. 当链表满的时候,将链表尾部的数据丢弃。
三、LFU
(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。
LFU的每个数据块都有一个引用计数,所有数据块按照引用计数排序,具有相同引用计数的数据块则按照时间排序。
具体实现如下:
1. 新加入数据插入到队列尾部(因为引用计数为1);
2. 队列中的数据被访问后,引用计数增加,队列重新排序;
3. 当需要淘汰数据时,将已经排序的列表最后的数据块删除。
前面两种算法实现并不算难,LFU实现起来会有点麻烦,下面是我自己考虑的淘汰实现思路,来了页面的时候会发生如下情况
1.判断是否有旧的页面存在,没有则淘汰尾部元素,增加新的元素。
2.有旧页面的存在,查询旧页面的位置,然后把旧页面的元素一直上移到同等次数的页面的上一个元素。
比如说元素(a,1)代表页面为a,调用次数为1,那么在缓存里面集合为{ (f,4), (e,2), (d,2), (c,2), (b,2), (a,1) },这时候调用c页面,只需要用折半查询找到c元素的位置,把c元素存储起来,把c元素到e元素之间的元素(不包含c元素)全部后移一位,然后把c元素放到原来e元素的位置即可。
下面附上三种算法的下载地址:
以上是关于Java 实现 FIFO 缓存算法的主要内容,如果未能解决你的问题,请参考以下文章
昨天面试被问到的 缓存淘汰算法FIFOLRULFU及Java实现