内容简介:LRU 是 Least Recently Used 的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最久未使用的页面予以淘汰。-百科本文说的 LRU 主要是指该算法在业务层的缓存算法中的应用,基本的实现逻辑是一样的。算法思想:
LRU 是 Least Recently Used 的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最久未使用的页面予以淘汰。-百科
本文说的 LRU 主要是指该算法在业务层的缓存算法中的应用,基本的实现逻辑是一样的。
How ?
算法思想:
- 1,新数据插入到链表头部。
- 2,每当缓存命中(即缓存数据被访问),则将数据移到链表头部。
- 3,当链表满的时候,将链表尾部的数据丢弃。
算法实现
class Node{ public Node(String key,String value){ this.key = key; this.value = value; } public Node pre; public Node next; public String key; public String value; } public class LRUCache { private Node head; private Node end; //缓存上限 private int limit; private HashMap map; public LRUCache(int limit) { this.limit = limit; map = new HashMap(); } public String get(String key) { Node node = map.get(key); if(node == null) { return null; } //调整node到尾部 refreshNode(node); return node.value; } public void put(String key, String value) { Node node = map.get(key); if(node == null) { //key不存在直接插入 while(map.size() >= limit) { //去除链表内的节点 String oldKey = removeNode(head); //去除map中的缓存 map.remove(oldKey); } node = new Node(key, value); //链表中加入节点 addNode(node); //map中加入节点 map.put(key, node); } else { //更新节点并调整到尾部 node.value = value; refreshNode(node); } } private void refreshNode(Node node) { //如果访问的是尾节点,无须移动节点 if(node == end) { return; } //把节点移动到尾部,相当于做一次删除插入操作 removeNode(node); addNode(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; } private void addNode(Node node) { if(end != null) { end.next = node; node.pre = end; node.next = null; } end = node; if(head == null) { head = node; } } }
JDK 中的算法实现
通常不需要我们自己专门实现一个此算法的数据结构,使用 JDK 内置的 LinkedHashMap 稍加改造即可。
public class LRUCache<K, V> extends LinkedHashMap<K, V> { private final int MAX_CACHE_SIZE; public LRUCache2(int cacheSize) { super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true); MAX_CACHE_SIZE = cacheSize; } @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_CACHE_SIZE; } }
mybatis 中的 LRU 算法实现
/** * 最近最少使用缓存 * 基于 LinkedHashMap 覆盖其 removeEldestEntry 方法实现。 */ public class LruCache implements Cache { private final Cache delegate; //额外用了一个map才做lru,但是委托的Cache里面其实也是一个map,这样等于用2倍的内存实现lru功能 private Map<Object, Object> keyMap; private Object eldestKey; public LruCache(Cache delegate) { this.delegate = delegate; setSize(1024); } @Override public String getId() { return delegate.getId(); } @Override public int getSize() { return delegate.getSize(); } public void setSize(final int size) { keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) { private static final long serialVersionUID = 4267176411845948333L; //核心就是覆盖 LinkedHashMap.removeEldestEntry方法, //返回true或false告诉 LinkedHashMap要不要删除此最老键值 //LinkedHashMap内部其实就是每次访问或者插入一个元素都会把元素放到链表末尾, //这样不经常访问的键值肯定就在链表开头啦 @Override protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) { boolean tooBig = size() > size; if (tooBig) { //这里没辙了,把eldestKey存入实例变量 eldestKey = eldest.getKey(); } return tooBig; } }; } @Override public void putObject(Object key, Object value) { delegate.putObject(key, value); //增加新纪录后,判断是否要将最老元素移除 cycleKeyList(key); } @Override public Object getObject(Object key) { //get的时候调用一下LinkedHashMap.get,让经常访问的值移动到链表末尾 keyMap.get(key); //touch return delegate.getObject(key); } @Override public Object removeObject(Object key) { return delegate.removeObject(key); } @Override public void clear() { delegate.clear(); keyMap.clear(); } @Override public ReadWriteLock getReadWriteLock() { return null; } private void cycleKeyList(Object key) { keyMap.put(key, key); //keyMap是linkedhashmap,最老的记录已经被移除了,然后这里我们还需要移除被委托的那个cache的记录 if (eldestKey != null) { delegate.removeObject(eldestKey); eldestKey = null; } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 通俗易懂--决策树算法、随机森林算法讲解(算法+案例)
- 限流算法之漏桶算法、令牌桶算法
- 什么是Paxos算法?Paxos算法是区块链核心算法之一
- 一文读懂对称加密算法、非对称加密算法和Hash算法
- 算法(六):图解贪婪算法
- 算法篇03:排序算法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
快速傅里叶变换
K. R. Rao、D. N. Kim、J. J. Hwang / 万帅、杨付正 / 机械工业出版社 / 2013-3 / 98.00元
《国际信息工程先进技术译丛·快速傅里叶变换:算法与应用》深入浅出地阐述了快速傅里叶变换(FFT)的原理,系统地总结了各类FFT算法,并广泛精辟地介绍了FFT在视频和音频信号处理中的各种应用。《国际信息工程先进技术译丛·快速傅里叶变换:算法与应用》在阐述了离散傅里叶变换(DFT)的原理和性质之后,详细讨论了时域抽取(DIT)和频域抽取(DIF)的各类快速算法。论述了近似计算DFT的整数FFT、二维及......一起来看看 《快速傅里叶变换》 这本书的介绍吧!