LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰

495 阅读2分钟
package com.LRU;

import java.util.StringJoiner;
import java.util.concurrent.ConcurrentHashMap;

public class LUR20210428<K,V> {

    /**
     * 初始化 LRU 缓存类
     *
     * @param cacheSize 缓存链的大小
     */
    LUR20210428(int cacheSize){
        //缓存链的大小
        this.cacheSize=cacheSize;
        //初始化 map 大小
        data=new ConcurrentHashMap<>(cacheSize);

        //初始化 链的头
        first=new Node();
        first.last=null;
        //初始化 链的尾
        penultimate=new Node();
        penultimate.nest=null;

        //初始化 链的头尾相连
        first.nest=penultimate;
        penultimate.last=first;
    }
    // 缓存数据的长度
    private int cacheSize;
    // 目前数据大小
    private int count=0;
    // 第一个节点
    private Node first;
    // 最后一个节点
    private Node penultimate;
    //存储数据的结构
    ConcurrentHashMap<K,Node> data;

    //存储数据的类
    class Node{
        Node last;
        Node nest;
        K key;
        V value;
    }
    //获取数据大小
    int getSize(){
        return count;
    }

    /**
     * 通过key获取数据
     * @param key
     * @return
     */
    public synchronized V get(K key){
        Node node = data.get(key);
        if(node==null){
            return null;
        }
        //如果数据不为null  删除链中的节点
        removeOne(node);
        // 然后把这个节点 添加到头部
        insertFirst(node);
        return  data.get(key).value;
    }

    /**
     * 添加缓存数据
     * @param key
     * @param value
     * @return
     */
    public synchronized Boolean put(K key,V value){
        Node node = data.get(key);
        if(node!=null){
            //已有该数据 则删除链中的数据  并把它添加到头部
            node.value=value;
            removeOne(node);
            insertFirst(node);
        }else {
            //没有该数据 则新建node  并把它添加到头部
            node = new Node();
            node.key=key;
            node.value=value;
            insertFirst(node);
        }
        //最后更新到map
        data.put(key,node);
        return true;
    }

    /**
     * 通过key删除节点
     * @param key
     * @return
     */
    public synchronized Boolean remove(K key){
        Node node = data.get(key);
        if(node!=null){
            removeOne(node);
            return true;
        }
        return false;
    }


    /**
     * 私有方法 把node添加到头部
     * @param node
     * @return
     */
    private Node insertFirst(Node node){

        //如果 数据大小 接近了 缓存设置大小 则删除最末尾的数据
        if (count>=cacheSize){
            removeLastOne();
        }
        // 把数据插到 first 后面的节点
        Node oldFirst = first.nest;
        oldFirst.last=node;
        node.nest=oldFirst;

        node.last=first;
        first.nest=node;
        count++;
        return node;
    }

    /**
     * 私有的 删除节点 并删除map中的数据
     * @param node
     */
    private void removeOne(Node node){
        data.remove(node.key);
        Node last= node.last;
        Node nest= node.nest;
        last.nest=nest;
        nest.last=last;
        count--;
    }

    /**
     * 私有化 删除末尾淘汰的节点
     */
    private void removeLastOne(){
        //先删除data中这个节点的数据
        data.remove(penultimate.last.key);
        // 然后 删除掉链中的末尾的数据
        Node needRemoveNode = penultimate.last;
        Node newPenultimate  = needRemoveNode.last;
        newPenultimate.nest=penultimate;
        penultimate.last=newPenultimate;
        count--;
    }


    /**
     * 可视化输出  链数量  和  链结构  方便查看运行过程
     */
    public void printLink(){
        StringJoiner stringJoiner=new StringJoiner(">");
        Node firstNode=first.nest;
        while (firstNode.nest!=null){
            stringJoiner.add(firstNode.key+"");
            firstNode=firstNode.nest;
        }
        System.out.println( "count :"+count+"|" + stringJoiner.toString());

    }
}

测试

package com.LRU;

import java.util.concurrent.locks.ReentrantLock;

public class test {
    public synchronized  static void main(String[] args) {

        LUR20210428<Integer,Integer> lruCache= new LUR20210428<Integer, Integer>(4);
        lruCache.put(1,10);
        lruCache.put(2,20);
        lruCache.put(3,30);

        lruCache.printLink();
        lruCache.put(4,40);
        lruCache.printLink();
        lruCache.put(4,40);
        lruCache.printLink();
        lruCache.put(4,40);
        lruCache.printLink();
        lruCache.put(5,50);
        lruCache.printLink();
        lruCache.remove(4);
        lruCache.remove(5);
        lruCache.printLink();


    }
}


修改添加了 map为线程安全

image.png