缓存淘汰策略

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]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值