Java LRU队列

引言

LRU(Least Recently Used)是一种常见的缓存淘汰策略,该策略会优先淘汰最近最少使用的缓存数据。在实际应用中,经常需要使用LRU队列来实现缓存系统,以提高性能和资源利用率。本文将介绍LRU队列的原理及其在Java中的实现方式。

LRU队列原理

LRU队列是一种基于哈希表和双向链表的数据结构,用于实现LRU缓存淘汰策略。其原理如下:

  1. 使用一个哈希表来存储缓存数据,哈希表的键为缓存的键,值为缓存的值。
  2. 使用一个双向链表来维护缓存数据的访问顺序,链表头部表示最近访问的数据,链表尾部表示最久未访问的数据。
  3. 当访问一个缓存数据时,如果数据存在于哈希表中,将其从原来的位置移动到链表头部;如果不存在于哈希表中,将其添加到链表头部,并将其添加到哈希表中。
  4. 当缓存数据达到一定大小时,需要淘汰链表尾部的数据,即最久未访问的数据。同时,需要从哈希表中删除该数据。

LRU队列实现

下面是一个简单的Java实现LRU队列的示例代码:

import java.util.HashMap;

class LRUCache {
    class Node {
        int key;
        int value;
        Node prev;
        Node next;
    }

    private int capacity;
    private HashMap<Integer, Node> cache;
    private Node head;
    private Node tail;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.cache = new HashMap<>();
        this.head = new Node();
        this.tail = new Node();
        this.head.next = this.tail;
        this.tail.prev = this.head;
    }

    public int get(int key) {
        Node node = cache.get(key);
        if (node != null) {
            // 将访问的节点移动到链表头部
            removeNode(node);
            addToHead(node);
            return node.value;
        }
        return -1;
    }

    public void put(int key, int value) {
        Node node = cache.get(key);
        if (node != null) {
            // 更新节点的值,并将节点移动到链表头部
            node.value = value;
            removeNode(node);
            addToHead(node);
        } else {
            if (cache.size() >= capacity) {
                // 链表尾部的节点为最久未访问的节点,需删除
                Node tailNode = tail.prev;
                removeNode(tailNode);
                cache.remove(tailNode.key);
            }
            // 添加新节点到链表头部
            Node newNode = new Node();
            newNode.key = key;
            newNode.value = value;
            cache.put(key, newNode);
            addToHead(newNode);
        }
    }

    private void removeNode(Node node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private void addToHead(Node node) {
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }
}

流程图

下面是LRU队列的流程图:

st=>start: 开始
op1=>operation: 创建LRU队列
op2=>operation: 访问缓存数据
op3=>operation: 添加缓存数据
op4=>operation: 删除缓存数据
cond1=>condition: 数据存在于哈希表中吗?
op5=>operation: 移动节点到链表头部
op6=>operation: 更新节点的值
op7=>operation: 移动节点到链表头部
op8=>operation: 创建新节点
op9=>operation: 删除链表尾部节点
op10=>operation: 添加新节点到链表头部
e=>end: 结束

st->op1->op2->cond1
cond1(yes)->op5->op2
cond1(no)->op8->op9->op10->op3
op3(right)->op2
op2(right)->op7->op2
op6(right)->op7->op2
op7(right)->op2
op9(right)->op4
op4->op10
op10(right)->op3
op3(no)->e
``