android开发-LRU缓存源码解析
来源:互联网 发布:怎么制作mac安装u盘 编辑:程序博客网 时间:2024/06/01 16:17
LRU ---- least recently used.顾名思义,是根据数据的活跃度进行更新的缓存算法。
Java里面实现LRU缓存通常有两种选择,
一种是使用LinkedHashMap,
一种是自己设计数据结构,使用链表+HashMap(线程不安全) 或者是链表+HashTable(线程安全)
一、LRU Cache的LinkedHashMap实现:
LinkedHashMap自身已经实现了顺序存储,默认情况下是按照元素的添加顺序存储,也可以启用按照访问顺序存储,即最近读取的数据放在最前面,最早读取的数据放在最后面,然后它还有一个判断是否删除最老数据的方法,默认是返回false,即不删除数据,我们使用LinkedHashMap实现LRU缓存的方法就是对LinkedHashMap实现简单的扩展,主要是扩展removeEldestEntry这个方法。
//LinkedHashMap自带的判断是否删除最老的元素方法,默认返回false,即不删除老数据//我们要做的就是重写这个方法,当满足一定条件时删除老数据protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return false;}扩展方式有两种,一种是inheritance(继承),一种是delegation(代理),具体使用什么方式看个人喜好1、inheritance(继承)
public class LRUCache2<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; } @Override public String toString() { StringBuilder sb = new StringBuilder(); for (Map.Entry<K, V> entry : entrySet()) { sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue())); } return sb.toString(); }}
2、delegation(代理)
public class LRUCache3<K, V> { private final int MAX_CACHE_SIZE; private final float DEFAULT_LOAD_FACTOR = 0.75f; LinkedHashMap<K, V> map; public LRUCache3(int cacheSize) { MAX_CACHE_SIZE = cacheSize; //根据cacheSize和加载因子计算hashmap的capactiy,+1确保当达到cacheSize上限时不会触发hashmap的扩容, int capacity = (int) Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTOR) + 1; map = new LinkedHashMap(capacity, DEFAULT_LOAD_FACTOR, true) { @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_CACHE_SIZE; } }; } public synchronized void put(K key, V value) { map.put(key, value); } public synchronized V get(K key) { return map.get(key); } public synchronized void remove(K key) { map.remove(key); } public synchronized Set<Map.Entry<K, V>> getAll() { return map.entrySet(); } public synchronized int size() { return map.size(); } public synchronized void clear() { map.clear(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); for (Map.Entry entry : map.entrySet()) { sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue())); } return sb.toString(); }}
三、双向链表+HashMap
public class LRUCache1<K, V> { private final int MAX_CACHE_SIZE; private Entry first; private Entry last; private HashMap<K, Entry<K, V>> hashMap; public LRUCache1(int cacheSize) { MAX_CACHE_SIZE = cacheSize; hashMap = new HashMap<K, Entry<K, V>>(); } public void put(K key, V value) { Entry entry = getEntry(key); if (entry == null) { if (hashMap.size() >= MAX_CACHE_SIZE) { hashMap.remove(last.key); removeLast(); } entry = new Entry(); entry.key = key; } entry.value = value; moveToFirst(entry); hashMap.put(key, entry); } public V get(K key) { Entry<K, V> entry = getEntry(key); if (entry == null) return null; moveToFirst(entry); return entry.value; } public void remove(K key) { Entry entry = getEntry(key); if (entry != null) { if (entry.pre != null) entry.pre.next = entry.next; if (entry.next != null) entry.next.pre = entry.pre; if (entry == first) first = entry.next; if (entry == last) last = entry.pre; } hashMap.remove(key); } private void moveToFirst(Entry entry) { if (entry == first) return; if (entry.pre != null) entry.pre.next = entry.next; if (entry.next != null) entry.next.pre = entry.pre; if (entry == last) last = last.pre; if (first == null || last == null) { first = last = entry; return; } entry.next = first; first.pre = entry; first = entry; entry.pre = null; } private void removeLast() { if (last != null) { last = last.pre; if (last == null) first = null; else last.next = null; } } private Entry<K, V> getEntry(K key) { return hashMap.get(key); } @Override public String toString() { StringBuilder sb = new StringBuilder(); Entry entry = first; while (entry != null) { sb.append(String.format("%s:%s ", entry.key, entry.value)); entry = entry.next; } return sb.toString(); } class Entry<K, V> { public Entry pre; public Entry next; public K key; public V value; }}
四、双向链表+HashTable
public class LRUCache {/** * 链表节点 * @author Administrator * */class CacheNode {CacheNode prev;//前一节点CacheNode next;//后一节点Object value;//值Object key;//键CacheNode() {}}public LRUCache(int i) {currentSize = 0;cacheSize = i;nodes = new Hashtable(i);//缓存容器}/** * 获取缓存中对象 * @param key * @return */public Object get(Object key) {CacheNode node = (CacheNode) nodes.get(key);if (node != null) {moveToHead(node);return node.value;} else {return null;}}/** * 添加缓存 * @param key * @param value */public void put(Object key, Object value) {CacheNode node = (CacheNode) nodes.get(key);if (node == null) {//缓存容器是否已经超过大小.if (currentSize >= cacheSize) {if (last != null)//将最少使用的删除nodes.remove(last.key);removeLast();} else {currentSize++;}node = new CacheNode();}node.value = value;node.key = key;//将最新使用的节点放到链表头,表示最新使用的.moveToHead(node);nodes.put(key, node);}/** * 将缓存删除 * @param key * @return */public Object remove(Object key) {CacheNode node = (CacheNode) nodes.get(key);if (node != null) {if (node.prev != null) {node.prev.next = node.next;}if (node.next != null) {node.next.prev = node.prev;}if (last == node)last = node.prev;if (first == node)first = node.next;}return node;}public void clear() {first = null;last = null;}/** * 删除链表尾部节点 * 表示 删除最少使用的缓存对象 */private void removeLast() {//链表尾不为空,则将链表尾指向null. 删除连表尾(删除最少使用的缓存对象)if (last != null) {if (last.prev != null)last.prev.next = null;elsefirst = null;last = last.prev;}}/** * 移动到链表头,表示这个节点是最新使用过的 * @param node */private void moveToHead(CacheNode node) {if (node == first)return;if (node.prev != null)node.prev.next = node.next;if (node.next != null)node.next.prev = node.prev;if (last == node)last = node.prev;if (first != null) {node.next = first;first.prev = node;}first = node;node.prev = null;if (last == null)last = first;}private int cacheSize;private Hashtable nodes;//缓存容器private int currentSize;private CacheNode first;//链表头private CacheNode last;//链表尾}
其实他们的原理都是差不多,都是双向链表+map的形式,Entry里面 都是包含了key,value,pre,next 这四个元素,只是LinkedHashMap已经实现了这些功能
然后通过访问的时候 改变他们的位置,他们的位置 就是通过修改 next与pre的值实现的
草考了这两篇文章:
LinkedHashMap
http://www.cnblogs.com/lzrabbit/p/3734850.html
双向链表+HashTable
http://gogole.iteye.com/blog/692103
阅读全文
0 0
- android开发-LRU缓存源码解析
- android lru缓存 辅助类LruCache源码解析
- Android缓存策略LruCahe源码解析,Lru到底是怎么算的?
- Android之Lru缓存
- Android LRU缓存算法实现
- Android--LRU缓存实现(Java)
- android开发常用的缓存策略详解(1)- LRU缓存策略
- android LruCache内存缓存源码解析
- Android-UIL图片缓存框架 源码解析
- Android内存缓存LruCache源码解析
- Android 源码解析-LruCache 缓存工具类
- Android 源码开发指令解析
- android开发-AsyncTask源码解析
- android开发-Hashmap源码解析
- LRU缓存
- LRU缓存
- LRU缓存
- 缓存-LRU
- 使用Ftp上传下载文件-Java版
- 二叉查找树,红黑树,AVL树,B~/B+树(B-tree),伸展树——优缺点及比较
- DHT网络中计算torrent资源热度的一种方法
- Shell简介:1分钟理解什么是Shell 脚本语言 解释器 以及编译器和编译语言
- 安装VMware tools时遇到的问题
- android开发-LRU缓存源码解析
- 概率 && 期望 入门
- LFS-Linux From Scratch学习笔记——构建LFS系统
- ubuntu16+gtx1050+anaconda+tensorflow
- 洛谷P2149 [SDOI2009]Elaxia的路线(最短路,拓扑排序)
- JavaScriptDOM练习之滚动条效果
- 低权用户调用高权用户创建的存储过程出错:noAccessToProcedureBodies
- UVALive
- Android-Gson使用详解