LRU(Least recently used),即最近最少使用算法,该算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
实现过程 1. 新数据将被插入到链表表头; 2. 访问缓存中的数据时,将该数据移动到链表表头; 3. 当链表满时,将链表尾部的数据丢弃。
页面置换算法 LRU 算法,是操作系统中一种典型的内存管理算法,常用于虚拟页式存储,这种页面置换算法的原理是,对于在内存中但又不用的数据块(内存块)叫做 LRU,操作系统会根据哪些数据属于 LRU 而将其移出内存,用于腾出空间来加载另外的数据。
看下面的一个例子:
一进程刚获得3个主存块的使用权,若该进程访问页面的次序是1、2、3、4、1、2、5、1、2、3、4、5。当采用LRU算法时,发生的缺页次数是 (10)
微信小程序 微信小程序列表采用的就是 LRU 算法,当用户访问一个列表中没有的小程序时,会将该小程序置于表头;同样地,当用户访问一个列表中存在的小程序时,会将该小程序移至表头。
LRU 的实现 首先,创建一个 Cache 基类:
public interface Cache<K, E> {
boolean put(K key, E value);
E get(Object o);
E remove(Object o);
void clear();
}
实现 LRU 算法:
public abstract class LruCache<K, E> implements Cache<K, E> {
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* 最大容量,总是大于 {@link #size}
*/
int capacity;
/**
* 当前元素总大小
*/
int size;
/**
* 所有元素
*/
LinkedHashMap<K, E> elements;
/**
* 获取单个元素的大小
*
* @param value
* @return
*/
protected int sizeOf(Object key, E value) {
return 1;
}
protected Collection<E> values() {
return elements.values();
}
public LruCache() {
this(DEFAULT_INITIAL_CAPACITY);
}
public LruCache(int capacity) {
if (capacity <= 0) {
throw new IllegalArgumentException("capacity cannot be less than or equals 0.");
}
this.capacity = capacity;
elements = new LinkedHashMap<>(0, DEFAULT_LOAD_FACTOR, true);
}
@Override
public boolean put(K key, E value) {
if (key == null || value == null) {
throw new NullPointerException("key or value cant be null.");
}
synchronized (this) {
E e = elements.put(key, value);
if (e == null) {
size += sizeOf(key, value);
}
}
trimEle();
return true;
}
protected void trimEle() {
K key;
E value;
for (; ; ) {
synchronized (this) {
if (size < 0) {
throw new ArithmeticException("total size is less than 0.");
}
if (elements.isEmpty() || size <= capacity) {
break;
}
Map.Entry<K, E> deleting = elements.entrySet().iterator().next();
if (deleting == null) {
break;
}
key = deleting.getKey();
value = deleting.getValue();
elements.remove(key);
size -= sizeOf(key, value);
}
}
}
@Override
public E get(Object key) {
if (key == null) {
throw new NullPointerException("key cant be null.");
}
synchronized (this) {
return elements.get(key);
}
}
@Override
public E remove(Object key) {
if (key == null) {
throw new NullPointerException("key cant be null.");
}
synchronized (this) {
E e = elements.remove(key);
if (e != null) {
size -= sizeOf(key, e);
}
return e;
}
}
@Override
public synchronized void clear() {
elements.clear();
size = 0;
}
/**
* 重置缓存限制大小
*
* @param capacity
*/
public void setupCapacity(int capacity) {
if(capacity <= 0) {
throw new IllegalArgumentException("capacity cannot be less than or equals 0.");
} else {
synchronized(this) {
this.capacity = capacity;
}
trimEle();
}
}
}
一个具体的 LRU 缓存对象,比如使用该算法缓存 Integer 对象:
public class IntegerLruCache extends LruCache<Integer, Integer> {
public IntegerLruCache() {
super();
}
public IntegerLruCache(int capacity) {
super(capacity);
}
@Override
protected int sizeOf(Object key, Integer value) {
return value;
}
/**
* 求和
*
* @return
*/
public int sum() {
int sum = 0;
Collection<Integer> values = values();
for (Integer num : values) {
sum += num;
}
return sum;
}
public static void main(String[] args) {
IntegerLruCache ilc = new IntegerLruCache(100);
ilc.put(1, 25);
ilc.put(2, 19);
ilc.put(3, 22);
System.out.println(ilc);
ilc.get(1);
System.out.println(ilc);
System.out.println(" " + ilc.sum());
ilc.put(4, 40);
System.out.println(ilc);
System.out.println(" " + ilc.sum());
}
}
print:
[25, 19, 22]
[19, 22, 25]
66
[22, 25, 40]
87
LRU 作为一种有效地缓存淘汰算法,在 Android 中常用于缓存图片对象。
本文由
知我者乎 原创,未经许可,不得转载!