淘汰策略
1. FIFO(First Input First Output 先进先出)
package com.lizq.springboot.cacheout;
import java.util.ArrayDeque;
import java.util.Queue;
/**
* FIFO (First Input First Output,先进先出)
*/
public class FIFOCacheOut {
// 数组:用于存储元素
private Object[] elements;
// 记录最大存储元素个数:默认为10
private int capacity = 10;
// 记录元素个数
private int position = 0;
public FIFOCacheOut(int capacity) {
this.capacity = capacity;
}
/**
* 添加元素
*
* @param obj
* @return 当前元素所在位置
*/
public int addElement(Object obj) {
if (elements == null) {
elements = new Object[capacity];
}
if (position == capacity) {// 队列已满,执行FIFO淘汰策略
Object[] a = new Object[capacity];
System.arraycopy(elements, 0, a, 1, 9);
elements = a;
position = capacity;
elements[0] = obj;
return 0;
}
// 队列未满
elements[position] = obj;
position++;
return position - 1;
}
/**
* 获取队头数据,不删除
*
* @return
*/
public Object poll() {
if (elements == null || position == 0) {
return null;
}
return elements[position - 1];
}
/**
* 获取队头数据,删除
*
* @return
*/
public Object pop() {
if (elements == null || position == 0) {
return null;
}
Object obj = elements[position - 1];
elements[position - 1] = null;
position--;
return obj;
}
public static void main(String[] args) {
Queue queue1 = new ArrayDeque();
queue1.poll();
FIFOCacheOut queue = new FIFOCacheOut(10);
for (int i = 1; i <= 15; i++) {
queue.addElement(i);
}
System.out.print("出队:");
while (queue.poll() != null){
System.out.print(queue.pop() + " ");
}
System.out.println();
}
}
结果:
出队:5 4 3 2 1 11 12 13 14 15
2. LFU(Least Frequently Used 最少使用的)
package com.lizq.springboot.cacheout;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* LFU(Least Frequently Used 最少使用的)
*/
public class LFUCacheOut<K, V> {
// 记录最大存储元素个数:默认为 5
private int capacity = 5;
// 记录存储的元素
private Map<K, V> elements = new HashMap<>();
// 记录元素被访问的次数
private Map<K, Integer> callNums = new HashMap<>();
public LFUCacheOut(int capacity) {
this.capacity = capacity;
}
/**
* 存放元素
*
* @param k
* @param v
*/
public void put(K k, V v) {
V v1 = elements.get(k);
if (v1 == null) {// 判断当前元素是否已经存在
if (this.capacity == elements.size()) {// 已满
// 删除访问次数最少的记录
removeCallMinNumObj();
elements.put(k, v);
callNums.put(k, 0);
} else {// 未满
elements.put(k, v);
callNums.put(k, 0);
}
}
}
/**
* 获取元素
*
* @param k
* @return
*/
public V get(K k) {
V v = elements.get(k);
callNums.computeIfPresent(k, (key, val) -> val == null ? 1 : val + 1);
return v;
}
/**
* 删除访问次数最少的记录
*/
private void removeCallMinNumObj() {
if (!elements.isEmpty()) {
int callNum = Integer.MAX_VALUE;
K key = null;
for (Map.Entry<K, Integer> entry : callNums.entrySet()) {
if (callNum >= entry.getValue()) {
callNum = entry.getValue();
key = entry.getKey();
}
}
callNums.remove(key);
elements.remove(key);
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
int capacity = 5;
LFUCacheOut lfuCacheOut = new LFUCacheOut<>(capacity);
for (int i = 0; i < capacity; i++) {
lfuCacheOut.put(i, "My name is key" + i);
}
Random random = new Random();
// 随机访问
for (int i = 0; i < 1000; i++){
lfuCacheOut.get(Math.abs(random.nextInt(10000)) % capacity);
}
System.out.println("当前队列中元素访问记录为:" + lfuCacheOut.callNums);
// 新增一个元素
lfuCacheOut.put("newKey1", "My name is newKey1");
System.out.println("当前队列中元素访问记录为:" + lfuCacheOut.callNums);
lfuCacheOut.put("newKey2", "My name is newKey2");
System.out.println("当前队列中元素访问记录为:" + lfuCacheOut.callNums);
}
}
结果:
当前队列中元素访问记录为:{0=192, 1=186, 2=220, 3=204, 4=198}
当前队列中元素访问记录为:{0=192, 2=220, 3=204, 4=198, newKey1=0}
当前队列中元素访问记录为:{0=192, 2=220, 3=204, 4=198, newKey2=0}
3. LRU(Least Recently Used 最久未使用的)
package com.lizq.springboot.cacheout;
import java.util.HashMap;
import java.util.Map;
/**
* LRU(Least Recently Used 最近最少使用算法)
*/
public class LRUCacheOut<K, V> {
// 记录最大存储元素个数
private int capacity = 5;
// 记录存储的元素
private Map<K, Node> elements;
// 定义虚拟头结点
private Node<K, V> firstNode;
// 定义虚拟尾结点
private Node<K, V> lastNode;
private class Node<K, V> {
private K key;
private V value;
// 下一个节点
private Node<K, V> nextNode;
// 上一个节点
private Node<K, V> preNode;
}
public LRUCacheOut(int capacity) {
this.capacity = capacity;
elements = new HashMap<>(capacity);
firstNode = new Node<>();
lastNode = new Node<>();
firstNode.nextNode = lastNode;
lastNode.preNode = firstNode;
}
public void put(K k, V v) {
if (elements == null) {
elements = new HashMap<>(capacity);
firstNode = new Node<>();
lastNode = new Node<>();
firstNode.nextNode = lastNode;
lastNode.preNode = firstNode;
}
Node node = elements.get(k);
if (node == null) {// 查不到
node = new Node();
node.key = k;
node.value = v;
elements.put(k, node);
if (elements.size() > capacity) {// 移除尾部元素
removeEndNode();
}
// 新增元素到双向链表到表头
addNode(node);
}else {
moveToHead(node);
}
}
public V get(K k) {
if (elements == null) {
return null;
}
Node<K, V> node = elements.get(k);
if (node != null) {// 获取获取到当前元素,则将当前元素移到到头部,并删除原来位置
moveToHead(node);
}
return node.value;
}
/**
* 新增元素到双向链表到表头
*
* @param node
*/
private void addNode(Node node) {
node.preNode = firstNode;
node.nextNode = firstNode.nextNode;
firstNode.nextNode.preNode = node;
firstNode.nextNode = node;
}
/**
* 将当前元素移到到头部,并删除原来位置
*
* @param node
*/
private void moveToHead(Node<K, V> node) {
node.preNode.nextNode = node.nextNode;
node.nextNode.preNode = node.preNode;
addNode(node);
}
/**
* 删除尾部节点
*/
private void removeEndNode() {
Node node = lastNode.preNode;
node.preNode.nextNode = lastNode;
lastNode.preNode = node.preNode;
elements.remove(node.key);
}
public static void main(String[] args){
LRUCacheOut lruCacheOut = new LRUCacheOut(3);
lruCacheOut.put(1, "test1");
lruCacheOut.put(2, "test2");
lruCacheOut.put(3, "test3");
lruCacheOut.get(1);
lruCacheOut.put(4, "test4");
System.out.println(lruCacheOut.elements.keySet());
}
}
结果:
[1, 3, 4]