MST

星途 面试题库

面试题:Java LinkedHashSet缓存场景下结合LRU策略的深度优化

在基于Java LinkedHashSet实现缓存且遵循LRU(最近最少使用)策略的基础上,当缓存数据量非常大且对内存占用敏感时,如何进一步优化LinkedHashSet的使用以提高缓存效率并减少内存开销?请详细说明优化思路、涉及的数据结构调整以及具体的代码实现要点。
15.3万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

优化思路

  1. 减少对象开销:LinkedHashSet内部存储的是完整的对象,若对象较大,可考虑仅存储对象的关键标识(如ID),在需要时再从其他数据源(如数据库)加载完整对象。
  2. 容量控制:设置合理的缓存容量上限,当达到上限时,按照LRU策略淘汰最久未使用的元素。
  3. 数据结构替换:LinkedHashSet虽然有序,但在大规模数据下,维护顺序和查找的开销较大。可结合其他数据结构来优化,如HashMap + 双向链表。

涉及的数据结构调整

  1. 双向链表:用于维护元素的访问顺序。链表头部表示最近访问的元素,链表尾部表示最久未使用的元素。
  2. HashMap:用于快速查找元素是否在缓存中。键为元素的标识,值为双向链表中对应节点的引用。

代码实现要点

  1. 定义双向链表节点类
class DLinkedNode {
    int key;
    int value;
    DLinkedNode prev;
    DLinkedNode next;
    public DLinkedNode() {}
    public DLinkedNode(int key, int value) {
        this.key = key;
        this.value = value;
    }
}
  1. 定义缓存类
public class LRUCache {
    private int capacity;
    private int size;
    private HashMap<Integer, DLinkedNode> cache = new HashMap<>();
    private DLinkedNode head;
    private DLinkedNode tail;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.size = 0;
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.prev = head;
    }

    private void moveToHead(DLinkedNode node) {
        removeNode(node);
        addToHead(node);
    }

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

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

    private DLinkedNode removeTail() {
        DLinkedNode node = tail.prev;
        removeNode(node);
        return node;
    }

    public int get(int key) {
        DLinkedNode node = cache.get(key);
        if (node == null) {
            return -1;
        }
        moveToHead(node);
        return node.value;
    }

    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);
        if (node == null) {
            DLinkedNode newNode = new DLinkedNode(key, value);
            cache.put(key, newNode);
            addToHead(newNode);
            size++;
            if (size > capacity) {
                DLinkedNode removed = removeTail();
                cache.remove(removed.key);
                size--;
            }
        } else {
            node.value = value;
            moveToHead(node);
        }
    }
}

通过这种方式,使用HashMap和双向链表的组合结构,在保证LRU策略的同时,提高了缓存效率并减少了内存开销。