缓存

一、介绍

1.1 什么是缓存

  • 缓存就是数据交换的缓冲区,当某一硬件要读取数据时,会首先从缓存中查询数据,有则直接执行,不存在时再从磁盘中读取。由于缓存的数据比磁盘快的多,所以缓存的作用就是帮助硬件更快的运行。
  • 缓存往往使用的是RAM(断电即掉的非永久存储),所以在用完以后还是会把文件送到硬盘等存储器中永久存储。电脑中最大的缓存就是内存条。
  • 高速缓存是用来协调CPU与主存之间存取速度的差异而设置的。一般CPU工作速度高,但内存的工作速度相对较低,为了解决这个问题,通常使用高速缓存,高速缓存的存取速度介于CPU与主存之间。系统将一些CPU在最近几个时间段经常访问的内容存在高速缓存,这样就在一定程度上缓解了由于主存速度低造成的CPU“停工待料”的情况。

1.2 缓存的作用

在不同的场景下,缓存的作用是不同的:

  • 操作系统磁盘缓存:减少磁盘机械操作
  • 数据库缓存:减少文件系统IO
  • 应用程序缓存:减少对数据库的查询
  • Web服务器缓存:减少应用服务器请求
  • 客户端浏览器缓存:减少对网站的访问

二、常见的缓存策略

2.1 LRU

Least Recently Used,称为最近最久未使用法,这种缓存机制会每次从内存中找到最久未使用的数据然后置换出来,从而存入新的数据。

实现:
LRU使用双向链表实现,主要涉及到添加、访问、修改、删除操作。首先是添加,如果是新元素,直接放在链表头上面,其他的元素顺序往下移动;访问的话,在头节点的可以不用管,如果是在中间位置或者尾巴,就要将数据移动到头节点;修改操作也是一样,修改原值之后,再将数据移动到头部,删除的话,直接删除,其他元素顺序移动

代码如下:

import java.util.HashMap;

class Node{
    Object key;
    Object value;
    Node pre;
    Node next;
    public Node(Object key,Object value){
        this.key=key;
        this.value=value;
    }
}

class LRU<K,V>{
    private int capcity;
    private HashMap<K,Node> caches;
    private Node first;
    private Node last;

    public LRU(int size){
        this.capcity=size;
        caches=new HashMap<K,Node>(size);
    }

    //添加元素
    public void put(K key,V value){
        Node node=caches.get(key);
        if(node==null){
            if(caches.size()>=capcity){
                caches.remove(last.key);
                removeLast();
            }
            node=new Node(key,value);
            caches.put(key,node);
        }
        else{
            node.value=value;
        }
        moveToHead(node);
    }

    //访问元素
    public Object get(K key){
        Node node=caches.get(key);
        if(node==null){
            return null;
        }
        moveToHead(node);
        return node.value;
    }

    //删除元素
    public Object remove(K key){
        Node node=caches.get(key);
        if(node!=null){
            if(node.pre!=null){
                node.pre.next=node.next;
            }
            if(node.next!=null){
                node.next.pre=node.pre;
            }
            if(node==first){
                first=first.next;
            }
            if(node==last){
                last=node.pre;
            }
        }
        return caches.remove(key);
    }

    public void moveToHead(Node node){
        if(first==node){
            return;
        }
        if(node.next!=null){
            node.next.pre=node.pre;
        }
        if(node.pre!=null){
            node.pre.next=node.next;
        }
        if(node==last){
            last=last.pre;
        }
        if(first==null||last==null){
            first=last=node;
            return;
        }
        node.next=first;
        first.pre=node;
        first=node;
        first.pre=null;
    }

    private void removeLast(){
        if(last!=null){
            last=last.pre;
            if(last==null){
                first=null;
            }
            else{
                last.next=null;
            }
        }
    }

    @Override
    public String toString(){
        StringBuilder sb=new StringBuilder();
        Node node=first;
        while(node!=null){
            sb.append(String.format("%s:%s",node.key,node.value)+" ");
            node=node.next;
        }
        return sb.toString();
    }


}

public class test{
    public static void main(String[] args) {
        LRU<Integer, String> lru = new LRU<Integer, String>(5);
        lru.put(1, "a");
        lru.put(2, "b");
        lru.put(3, "c");
        lru.put(4,"d");
        lru.put(5,"e");
        System.out.println("原始链表为:"+lru.toString());

        lru.get(4);
        System.out.println("获取key为4的元素之后的链表:"+lru.toString());

        lru.put(6,"f");
        System.out.println("新添加一个key为6之后的链表:"+lru.toString());

        lru.remove(3);
        System.out.println("移除key=3的之后的链表:"+lru.toString());
    }
}

输出结果:

原始链表为:5:e 4:d 3:c 2:b 1:a 
获取key为4的元素之后的链表:4:d 5:e 3:c 2:b 1:a 
新添加一个key为6之后的链表:6:f 4:d 5:e 3:c 2:b 
移除key=3的之后的链表:6:f 4:d 5:e 2:b 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值