在LRU缓存java实现中遇到未命中时设置操作

在LRU缓存java实现中遇到未命中时设置操作,java,caching,hashmap,doubly-linked-list,lru,Java,Caching,Hashmap,Doubly Linked List,Lru,我使用自己的DoublyLinkedList实现在Java中实现LRU缓存,该节点具有整数键和值,其中键表示页面标识符,值表示其在磁盘上的位置。另外,我使用Hashmap进行O(1)访问。我知道以下实施的基本知识: 如果请求的键是缓存命中,则返回其值(即其位置)并将此节点移动到DoublyLink列表的前面 如果是失误,我对另一个重要方面有疑问。根据各种资源,如果未命中,则在我的情况下,关键的页码设置为LinkedList的开头,在执行此操作时,如果遇到容量已满,则删除末尾的元素,然后将其输入到

我使用自己的DoublyLinkedList实现在Java中实现LRU缓存,该节点具有整数键和值,其中键表示页面标识符,值表示其在磁盘上的位置。另外,我使用Hashmap进行O(1)访问。我知道以下实施的基本知识:

如果请求的键是缓存命中,则返回其值(即其位置)并将此节点移动到DoublyLink列表的前面

如果是失误,我对另一个重要方面有疑问。根据各种资源,如果未命中,则在我的情况下,关键的页码设置为LinkedList的开头,在执行此操作时,如果遇到容量已满,则删除末尾的元素,然后将其输入到前面。现在为了实现,当我将页码(即键)放入缓存时,它的“值”应该是什么?我应该把它设为垃圾吗?在我下面介绍的“get”方法的实现中,我当前返回-1,但未命中

此外,在LRU缓存的实际生产代码中,缓存是否包含存储在这些页码处的页码或实际值?T

请帮我弄清楚这方面。谢谢

import java.util.HashMap;


public class LRU {

private static class Node {

    Node previous;
    Node next;
    int key;
    int value;

    public Node(int key, int value) {
        this.key = key;
        this.value = value;
    }
}

Node head = null;
Node tail = null;

HashMap<Integer, Node> hmap = new HashMap<>();

public int get(int key) {
    if (hmap.containsKey(key)) {
        Node n = hmap.get(key);
        remove(n);
        moveToFront(n);
        return n.value;
    }
    return -1;
}

public void remove(Node n) {
    // if n is head
    if (n.previous == null) {
        head = head.next;
    } else {
        n.previous.next = n.next;
    }

    //if n is tail
    if (n.next == null) {
        tail = n.previous;
    } else {
        n.next.previous = n.previous;

    }
}

public void moveToFront(Node n) {
    if(n==head)
        return;
    if(n.next==null)
    {
        n.previous.next=n.next;
        tail = n.previous;                    
        n.previous = null;
        n.next = head;
        head = n;
    }
    else {
        n.previous.next=n.next;
        n.next.previous=n.previous;
    }
}

public void set(int key, int value) {

   }
}
import java.util.HashMap;
公共级LRU{
私有静态类节点{
节点前向;
节点下一步;
int键;
int值;
公共节点(int键,int值){
this.key=key;
这个值=值;
}
}
节点头=空;
节点尾=空;
HashMap hmap=新的HashMap();
公共整数获取(整数密钥){
如果(hmap.CONTANSKEY(关键)){
节点n=hmap.get(key);
移除(n);
向前移动(n);
返回n.value;
}
返回-1;
}
公共无效删除(节点n){
//如果n是头
如果(n.previous==null){
head=head.next;
}否则{
n、 previous.next=n.next;
}
//如果n是尾
如果(n.next==null){
尾=n.前一个;
}否则{
n、 next.previous=n.previous;
}
}
公共void moveToFront(节点n){
如果(n==水头)
返回;
如果(n.next==null)
{
n、 上一个。下一个=下一个;
尾=n.前一个;
n、 previous=null;
n、 下一个=头部;
水头=n;
}
否则{
n、 上一个。下一个=下一个;
n、 next.previous=n.previous;
}
}
公共无效集(int键,int值){
}
}

术语缓存通常表示容量有限的键值对映射。当达到容量时,尝试添加一个新的键值对将导致退出一个现有的键值对,并添加新的键值对。通常,对的添加也是隐式进行的,作为尝试检索当前未存储在缓存中的密钥的值的函数(即缓存执行逐出、加载新对并返回值)

LRU(最近最少使用)是选择要逐出的对的可能策略之一,而不是唯一的策略。处理器数据高速缓存是在硬件中实现的高速缓存的一个示例,其中密钥从地址获得(通常仅考虑特定数量的最高有效位),并且该值是包含该地址的存储器的一部分。在这种情况下,高速缓存线包含驻留在存储器中的数据的副本。 另一个例子是,在支持虚拟内存的操作系统中,操作系统分页是作为硬件(MMU)和操作系统内核中的软件的组合实现的。在本例中,与您描述的更接近,该对的值是承载虚拟页的内存页的物理地址


因此,当你问“同样,在LRU缓存的实际生产代码中,缓存是否包含存储在这些页码处的页码或实际值?T”,答案可能取决于我们谈论的缓存。在您的情况下,不清楚缓存所支持的是什么。我假设它是某个文件中的偏移量。在这种情况下,我希望您的值是表示文件一部分的字节数组或字符串。对文件中偏移量x的访问将映射到key=offset/PAGE\u SIZE;如果表中不存在密钥,并且表已满,则可以“回收”最后一个节点,设置替换现有密钥,读取字节缓冲区中偏移量(密钥,密钥+页面大小-1)处的文件内容,最后将页面作为第一个移动。

在“实际生产代码”中,您使用
LinkedHashMap
,而不是推出自己的代码。除此之外,插入表示不存在条目的节点没有任何意义。此时,您只描述了一种映射,没有说明“页码”或“存储在这些页码上的实际值”的含义。所以不要问任何问题,是你决定需要缓存这些数据的。请放轻松。这里是新手。理解我们不能回答你没有解释的关于你的应用程序的问题与成为“新手”无关。创建LRU缓存与子类化
LinkedHashMap
一样简单,使用with
true
,因此点击将条目移动到前端并覆盖其文档中已经显示了如何执行固定大小的内容。这太棒了!就在最后一行:“读取字节缓冲区中偏移量(key,key+PAGE_SIZE-1)处的文件内容”-偏移量(key+PAGE_SIZE-1)表示什么?如果内存是字节寻址的,那么我们不是只读取该地址的单个字节吗?假设您有8Kb的页面。用户请求读取偏移量为9000的字节。页面索引为9000/8192=1。缓存替换代码应包含整个第1页,即范围(81928192+8191)。然后,代码返回该页中偏移量为9000%8192=808的字节。现在有意义了。谢谢!