Files
hutool/hutool-cache/src/main/java/cn/hutool/cache/impl/LFUCache.java

96 lines
2.3 KiB
Java
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package cn.hutool.cache.impl;
import java.util.HashMap;
import java.util.Iterator;
/**
* LFU(least frequently used) 最少使用率缓存<br>
* 根据使用次数来判定对象是否被持续缓存<br>
* 使用率是通过访问次数计算的。<br>
* 当缓存满时清理过期对象。<br>
* 清理后依旧满的情况下清除最少访问(访问计数最小)的对象并将其他对象的访问数减去这个最小访问数,以便新对象进入后可以公平计数。
*
* @author Looly,jodd
*
* @param <K> 键类型
* @param <V> 值类型
*/
public class LFUCache<K, V> extends ReentrantCache<K, V> {
private static final long serialVersionUID = 1L;
/**
* 构造
*
* @param capacity 容量
*/
public LFUCache(int capacity) {
this(capacity, 0);
}
/**
* 构造
*
* @param capacity 容量
* @param timeout 过期时长
*/
public LFUCache(int capacity, long timeout) {
if(Integer.MAX_VALUE == capacity) {
capacity -= 1;
}
this.capacity = capacity;
this.timeout = timeout;
cacheMap = new HashMap<>(capacity + 1, 1.0f);
}
// ---------------------------------------------------------------- prune
/**
* 清理过期对象。<br>
* 清理后依旧满的情况下清除最少访问(访问计数最小)的对象并将其他对象的访问数减去这个最小访问数,以便新对象进入后可以公平计数。
*
* @return 清理个数
*/
@Override
protected int pruneCache() {
int count = 0;
CacheObj<K, V> comin = null;
// 清理过期对象并找出访问最少的对象
Iterator<CacheObj<K, V>> values = cacheObjIter();
CacheObj<K, V> co;
while (values.hasNext()) {
co = values.next();
if (co.isExpired() == true) {
values.remove();
onRemove(co.key, co.obj);
count++;
continue;
}
//找出访问最少的对象
if (comin == null || co.accessCount.get() < comin.accessCount.get()) {
comin = co;
}
}
// 减少所有对象访问量并清除减少后为0的访问对象
if (isFull() && comin != null) {
long minAccessCount = comin.accessCount.get();
values = cacheObjIter();
CacheObj<K, V> co1;
while (values.hasNext()) {
co1 = values.next();
if (co1.accessCount.addAndGet(-minAccessCount) <= 0) {
values.remove();
onRemove(co1.key, co1.obj);
count++;
}
}
}
return count;
}
}