自己动手实现LRU、FIFO缓存淘汰算法, LinkedHashMap的妙用

自己动手实现LRU、FIFO缓存淘汰算法, LinkedHashMap的妙用

  **LRU(Least recently used,最近最少使用)**算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
  FIFO(First Input First Output,先进先出),即先进先出队列。在超市购物之后会提着我们满满的购物车来到收银台排在结账队伍的最后,眼睁睁地看着前面的客户一个个离开。这就是一种先进先出机制,先排队的客户先行结账离开。

  为了实现LRUFIFO算法,现在我们的LinkedHashMap就闪亮登场了,它虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,LinkedHashMap保证了元素迭代的顺序。该迭代顺序可以是插入顺序或者是访问顺序。于是LRU、FIFO缓存工具类的代码如下,该类的构造函数cacheSize表示缓存大小、accessOrder代表是否按照访问顺序存储(该参数值为true的时候,实现的是LRU算法;值为false时,实现的是FIFO算法)。

缓存工具类

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * LRU缓存实现
 * @author Java架构师养成记
 * @param <K>
 * @param <V>
 * */
public class CacheTools<K,V> {
    private final int initCacheSize;
    private final float DEFAULT_LOAD_FACTOR = 0.75f;

    LinkedHashMap<K, V> cacheMap;

    /**
     * 缓存工具类构造方法
     * @param  cacheSize 缓存大小
     * @param  accessOrder 是否翻找访问顺序存放(false:按照插入顺序存放)
     * */
    public CacheTools(int cacheSize, boolean accessOrder) {
        initCacheSize = cacheSize;
        int capacity = (int)Math.ceil(initCacheSize / DEFAULT_LOAD_FACTOR) + 1;
        cacheMap = new LinkedHashMap<K, V>(capacity, DEFAULT_LOAD_FACTOR, accessOrder) {
            @Override
            protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
                return size() > initCacheSize;
            }
        };
    }

    public synchronized void put(K key, V value) {
        cacheMap.put(key, value);
    }

    public synchronized V get(K key) {
        return cacheMap.get(key);
    }

    public synchronized void remove(K key) {
        cacheMap.remove(key);
    }

    public synchronized Set<Map.Entry<K, V>> getAll() {
        return cacheMap.entrySet();
    }

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map.Entry<K, V> entry : cacheMap.entrySet()) {
            stringBuilder.append(String.format("%s:%s", entry.getKey(), entry.getValue()));
            stringBuilder.append("|");
        }
        return stringBuilder.toString().substring(0, stringBuilder.toString().length() - 1);
    }
}

  LRUCache使用方法

public class LRUCache {
    public static void main(String[] args) {
        CacheTools<Object, Object> lruCache = new CacheTools<>(5, true);
        lruCache.put("Key1", "value1");
        lruCache.put("Key2", "value2");
        lruCache.put("Key3", "value3");
        lruCache.put("Key4", "value4");
        lruCache.put("Key5", "value5");
        System.out.println("未访问之前:" + lruCache);
        lruCache.get("Key1");
        System.out.println("访问之后:" + lruCache);
        lruCache.put("Key6", "value6");
        System.out.println("容量过大之后:" + lruCache);
    }
}

  LRU Cache效果截图:
TIM图片20190607212057.png
FIFoCache使用方法:

public class FIFOCache {
    public static void main(String[] args) {
        CacheTools<Object, Object> fifoCache = new CacheTools<>(5, false);
        fifoCache.put("Key1", "value1");
        fifoCache.put("Key2", "value2");
        fifoCache.put("Key3", "value3");
        fifoCache.put("Key4", "value4");
        fifoCache.put("Key5", "value5");
        System.out.println("未访问之前\t:" + fifoCache);
        fifoCache.get("Key1");
        System.out.println("访问之后\t\t:" + fifoCache);
        fifoCache.put("Key6", "value6");
        System.out.println("容量过大之后\t:" + fifoCache);
    }
}

  FIFO Cache效果截图:
TIM图片20190607212551.png
  从上文代码可以知道,LRU和FIFO缓存的区别在于accessOrder参数的设置,当该参数被设置为true的时候,表示该Cache的思想是LRU,否则是FIFO。

  欢迎大家关注我的微信公众号,不定期分享各类面试题。
Java架构师养成记.jpg

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值