Java LRU的简单实现

什么是LRU,参考:LRU算法 缓存淘汰策略

基于LinkedHashMap实现

LinkedHashMap本身就基于双向链表实现,而且就更新和记录最新访问元素,所以基于LinkedListHashMap我们只要重写removeEldestEntry方法即可,该方法的意思是,移除最旧的元素。

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

/**
 * date: 2020/9/27
 * description: LRUSimpleCache
 *
 * @author xiaopihai7256
 */
public class LRUSimpleCache extends LinkedHashMap {

    private static final long serialVersionUID = 23094571L;
    private final int maxCacheSize;

    LRUSimpleCache(int initialCapacity, int maxCacheSize) {
        super(initialCapacity, 0.75F, true);
        this.maxCacheSize = maxCacheSize;
    }

    protected boolean removeEldestEntry(Map.Entry eldest) {
        return this.size() > this.maxCacheSize;
    }

    // 简单测试
    public static void main(String[] args) {
        final var lruCache = new LRUSimpleCache<>(3, 3);
        lruCache.put("test1", 1);
        lruCache.put("test2", 2);
        System.out.println(lruCache.toString());
        lruCache.get("test1");
        System.out.println(lruCache.toString());
        lruCache.put("test3", 3);
        lruCache.put("test4", 1);
        lruCache.put("test5", 2);
        lruCache.put("test4", 2);
        System.out.println(lruCache.toString());
    }
}

2. 基于双向链表和HashMap实现

import java.util.HashMap;
import java.util.Map;

/**
 * date: 2020/9/27
 * description: 双向连标+map实现
 * @author xiaopihai7256
 */

public class LRUCache {
    // 简单测试
    public static void main(String[] args) {

        LRUCache cache2 = new LRUCache<>(3);
        cache2.put("test1", 1);
        System.out.println(cache2);
        cache2.put("test2", 2);
        System.out.println(cache2);
        cache2.put("test3", 3);
        System.out.println(cache2);
        cache2.get("test1");
        System.out.println(cache2);
        cache2.put("test2", 5);
        System.out.println(cache2);
        cache2.delete("test2");
        System.out.println(cache2);
        System.out.println(cache2.getHead());
        System.out.println(cache2.getLast());

    }

    /**
     * 首尾标志元素
     * lruNode.pre -> last
     * lruNode.next -> head
     */
    private final Node lruNode;
    /**
     * hash访问缓存
     */
    private final Map> cache;
    /**
     * LRU size
     */
    private final int size;

    public LRUCache(int size) {
        lruNode = new Node<>(null);
        cache = new HashMap<>(size <= 16 ? size : 16, 0.75f);
        this.size = size;
    }

    /**
     * 普通获取,被命中元素移动到队尾
     * @param key key
     * @return T value
     */
    public T get(K key) {
        Node node = cache.get(key);
        if (node == null) {
            return null;
        } else {
            if (node != lruNode.pre) {
                removeFromChain(node);
                appendToChain(node);
            }
            return node.value;
        }
    }
  
    // 添加或者更新元素,被操作的元素插入/移动到队尾
    public void put(K key, T value) {
        final Node cacheNode = cache.get(key);
        // 无缓存历史,则new一个,按照存储是否满了决定添加方式
        if (cacheNode == null) {
            Node node = new Node<>(value);
            if (cache.size() >= size) {
                Node head = lruNode.next;
                removeFromChain(head);
                appendToChain(node);
            } else {
                appendToChain(node);
            }
            cache.put(key, node);
        } else { // 存在缓存,则直接更新缓存,并移动到队尾
            // modified value
            cacheNode.value = value;
            // move to last
            removeFromChain(cacheNode);
            appendToChain(cacheNode);
        }
    }
    // 删除元素,被删除元素如果存在,从队列中移除
    public void delete(K key) {
        final Node node = cache.remove(key);
        if (node != null) {
            node.pre.next = node.next;
            node.next.pre = node.pre;
        }
    }
 
    private void removeFromChain(Node node) {
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }

    private void appendToChain(Node node) {
        Node last = lruNode.pre;
        if (last == null) {
            lruNode.next = node;
            node.pre = lruNode;
        } else {
            last.next = node;
            node.pre = last;
        }
        node.next = lruNode;
        lruNode.pre = node;

    }

    // 头部元素
    public T getHead() {
        return lruNode.next == null ? null : lruNode.next.value;
    }

    /**
     * 也是最后添加的或者访问过的元素
     * @return last ele
     */
    public T getLast() {
        return lruNode.pre == null ? null : lruNode.pre.value;
    }

    @Override
    public String toString() {
        Node node = lruNode.next;
        if (node == null) return "null";
        StringBuilder builder = new StringBuilder();
        while (node != lruNode.pre) {
            builder.append(node.toString()).append(" => ");
            node = node.next;
        }
        builder.append(node.toString());
        return builder.toString();
    }

    /**
     * node节点
     * @param 
     */
    public static class Node {

        private T value;
        Node pre;
        Node next;

        public Node(T value) {
            this.value = value;
            this.pre = null;
            this.next = null;
        }

        @Override
        public String toString() {
            return value == null ? "null" : value.toString();
        }
    }
}

你可能感兴趣的:(Java LRU的简单实现)