当前位置: 首页 > news >正文

LRUCache

请简述LRUcache原理,及常见应用场景。使用常用的java数据结构实现。

LRU(Least Recently Used)缓存算法是近期最少使用算法,其核心思想是当缓存满时,会优先淘汰那些近期最少使用的缓存对象。主要算法原理是把最近使用的对象强引用存储在LinkedHashMap中,当缓存满时,把最近最少使用的对象从内存中移除,并提供了get和put方法来完成缓存的获取和添加操作。

1、LRU的LinkedHashMap同步锁实现

package com.boomoom.service.localDataMap
import java.util.LinkedHashMap;
import java.util.Map;

public class LRUCache<K, V> {
    private static final float hashLoadFactory = 0.75f;
    private LinkedHashMap<K, V> map;
    private int cacheSize;

    public LRUCache(int cacheSize) {
     this.cacheSize = cacheSize;
        int capacity = (int)Math.ceil(cacheSize / hashLoadFactory) + 1;
        map = new LinkedHashMap<K, V>(capacity, hashLoadFactory, true) {
            private static final long serialVersionID = 1;

            @Override
            protected boolean removeEldestEntry(Map.Entry eldest) {
                return size() > LRUCache.this.cacheSize;
            }
        };
    }

    public V get(K key) {
        sychronized(this) {
            return map.get(key);
        }
    }

    public void put(K key, V value) {
        sychronized(this) {
            map.put(key, value);
        }
    }

    public void remove(Object key) {
        sychronized(this) {
            map.remove(key);
        }
    }

    public void clear() {
        sychronized(this) {
            map.clear();
        }
    }
}

2、LRU的LinkedHashMap读写锁实现

package com.boomoom.service.localDataMap
import java.util.LinkedHashMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class LruCache<K, V> {
    private int MAX_LENGTH = 1 << 30;  //最大长度
    private LinkedHashMap<K, V> map;
    private ReadWriteLock lock = new ReentrantReadWriteLock(); //读写锁

    public LruCache(int initLength) {
        this(initLength, MAX_LENGTH);
    }

    public LruCache(int initLength, int maxLength) {
        MAX_LENGTH = maxLength;
        map = new LinkedHashMap<K, V>(initLength, 0.75f, true) {
            @Override
            protected boolean removeEldestEntry(Entry<K, V> eldest) {
                return size() > MAX_LENGTH;
            }
        };
    }

    /**
     * 添加项
     *
     * @param item  项
     * @param state 状态
     */
    public void put(K item, V state) {
        lock.writeLock().lock();
        map.put(item, state);
        lock.writeLock().unlock();
    }

    /**
     * 获取值,使用前请判断是否存在item
     *
     * @param item 项
     * @return value 值
     */
    public V get(String item) {
        lock.readLock().lock();
        V value = map.get(item);
        lock.readLock().unlock();
        return value;
    }

    /**
     * 是否存在
     *
     * @param item 项
     * @return 是否存在
     */
    public boolean containsKey(String item) {
        lock.readLock().lock();
        boolean isContainer = map.containsKey(item);
        lock.readLock().unlock();
        return isContainer;
    }

    /**
     * 删除item
     *
     * @param item 项
     */
    public void remove(String item) {
        lock.writeLock().lock();
        map.remove(item);
        lock.writeLock().unlock();
    }
}

synchronized和ReadWriteLock的区别在于:

ReadWriteLock读写锁,当读取的时候线程会获得read锁,其他线程也可以获得read锁同时并发的去读取,但是写程序运行获取到write锁的时候,其他线程是不能进行操作的,因为write是排它锁,而synchronized不管你是read还是write没有抢到锁的线程都会被阻塞。

3、LRUCache的hashMap实现

需要注意的是,这段不是线程安全的,要想做到线程安全,同上两例需要加上synchronized等。

public class LRUCache<K, V> {

    private Node head;
    private Node end;
    //缓存存储上限
    private int  limit;

    private HashMap<String, Node> hashMap;

    public LRUCache(int limit) {
        this.limit = limit;
        hashMap = new HashMap<String, Node>();
    }

    public String get(String key) {
        Node node = hashMap.get(key);
        if (node == null) {
            return null;
        }
        refreshNode(node);
        return node.value;
    }

    public void put(String key, String value) {
        Node node = hashMap.get(key);
        if (node == null) {
            //如果key不存在,插入key-value
            if (hashMap.size() >= limit) {
                String oldKey = removeNode(head);
                hashMap.remove(oldKey);
            }
            node = new Node(key, value);
            addNode(node);
            hashMap.put(key, node);
        } else {
            //如果key存在,刷新key-value
            node.value = value;
            refreshNode(node);
        }
    }

    public void remove(String key) {
        Node node = hashMap.get(key);
        removeNode(node);
        hashMap.remove(key);
    }

    /**
     * 刷新被访问的节点位置
     *
     * @param node 被访问的节点
     */

    private void refreshNode(Node node) {
        //如果访问的是尾节点,无需移动节点
        if (node == end) {
            return;
        }
        //移除节点
        removeNode(node);
        //重新插入节点
        addNode(node);
    }

    /**
     * 删除节点
     *
     * @param node 要删除的节点
     */

    private String removeNode(Node node) {
        if (node == end) {
            //移除尾节点
            end = end.pre;
        } else if (node == head) {
            //移除头节点
            head = head.next;
        } else {
            //移除中间节点
            node.pre.next = node.next;
            node.next.pre = node.pre;
        }
        return node.key;
    }

    /**
     * 尾部插入节点
     *
     * @param node 要插入的节点
     */

    private void addNode(Node node) {
        if (end != null) {
            end.next = node;
            node.pre = end;
            node.next = null;
        }
        end = node;
        if (head == null) {
            head = node;
        }
    }

    class Node {
        Node(String key, String value) {
            this.key = key;
            this.value = value;
        }

        public Node   pre;
        public Node   next;
        public String key;
        public String value;
    }

    public static void main(String[] args) {
        LRUCache lruCache = new LRUCache(5);
        lruCache.put("001", "用户1信息");
        lruCache.put("002", "用户1信息");
        lruCache.put("003", "用户1信息");
        lruCache.put("004", "用户1信息");
        lruCache.put("005", "用户1信息");
        lruCache.get("002");
        lruCache.put("004", "用户2信息更新");
        lruCache.put("006", "用户6信息");
        System.out.println(lruCache.get("001"));
        System.out.println(lruCache.get("006"));
    }
}
LRUCache

 

 

 

转载于:https://www.cnblogs.com/boomoom/p/9919973.html

相关文章:

  • Hello, world!
  • Git 更改远程地址
  • 三十岁前不要去在乎的29件事
  • 转:面对一个全新的环境,作为一个Oracle DBA,首先应该了解什么
  • 什么是I2C管理总线
  • Java多线程系列---“JUC锁”03之 Condition
  • Junit Test 的时候出错java.lang.IllegalStateException: Failed to load ApplicationContext
  • 小教练教MM如何去掉你的小肚子
  • vue cli 3 webpack-merge webpack 3 bug
  • 一句话介绍python线程、进程和协程
  • ASP.NET中上传并读取Excel文件数据
  • 在 ISA Server 2004 中发布 ××× 服务器
  • Linux Command
  • ACM-ICPC 2018 青岛赛区现场赛 D. Magic Multiplication ZOJ 4061 (思维+构造)
  • 实战 HTTP 处理程序(HTTP Handler) (4)--与Web程序共享Session
  • 2017-08-04 前端日报
  • Android Volley源码解析
  • Android开源项目规范总结
  • CSS居中完全指南——构建CSS居中决策树
  • flask接收请求并推入栈
  • Java多态
  • PermissionScope Swift4 兼容问题
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • Python利用正则抓取网页内容保存到本地
  • Vue UI框架库开发介绍
  • 聊聊redis的数据结构的应用
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • 温故知新之javascript面向对象
  • 用quicker-worker.js轻松跑一个大数据遍历
  • 源码安装memcached和php memcache扩展
  • 中文输入法与React文本输入框的问题与解决方案
  • elasticsearch-head插件安装
  • ###C语言程序设计-----C语言学习(6)#
  • #NOIP 2014# day.2 T2 寻找道路
  • #pragma data_seg 共享数据区(转)
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (3)llvm ir转换过程
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (python)数据结构---字典
  • (react踩过的坑)Antd Select(设置了labelInValue)在FormItem中initialValue的问题
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (solr系列:一)使用tomcat部署solr服务
  • (ZT)薛涌:谈贫说富
  • (八十八)VFL语言初步 - 实现布局
  • (二)PySpark3:SparkSQL编程
  • (图)IntelliTrace Tools 跟踪云端程序
  • (转)C#调用WebService 基础
  • (转)socket Aio demo
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • .NET C#版本和.NET版本以及VS版本的对应关系
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .NET框架设计—常被忽视的C#设计技巧