Monitor
在框架內部由一個後臺的守護線程實現,基於用戶的配置定時執行緩存淘汰任務,定義如下:
/**
* 緩存淘汰監控器
*/
public interface Monitor {
void processMonitor();
void start();
void stop();
void startIfStop();
boolean isRunning();
}
當前版本框架提供了2種實現,TtlMonitor和CapMonitor,分別爲基於時間策略和基於容量策略。
TtlMonitor
@Override
public void processMonitor() {
long timeNow = System.currentTimeMillis();
for (CacheObject<K, V> o : delegate.values()) {
if (ttl <= 0) {
continue;
}
long timeIdle = timeNow - o.getInitializationTime();
if (timeIdle >= ttl) {
delegate.remove(o.getKey());
for (CacheListener<K, V> listener : listeners) {
listener.callback(new Payload<>(o.getKey(), o.getValue(), o.getInitializationTime()));
}
}
}
}
具體的淘汰策略是後臺線程會遍歷緩存對象集合,根據其initializationTime屬性與currentTime做差值,然後對比ttl,過期者,被移除,並調用CacheListener的callback方法,將被移除對象的相關信息返回給上層。
CapMonitor
@Override
public void processMonitor() {
int size = delegate.size();
if (size >= maximum) {
Map<Long, Object> sortMap = new TreeMap<>();
for (CacheObject<K, V> object : delegate.values()) {
sortMap.put(object.getLastAccessTime(), object.getKey());
}
Set<Long> keySet = sortMap.keySet();
Iterator<Long> it = keySet.iterator();
int count = 0;
int clearSize = (int) (maximum * clearFactor) + size - maximum;
while ((count < clearSize) && it.hasNext()) {
Object v = sortMap.get(it.next());
for (CacheListener<K, V> listener : listeners) {
listener.callback(new Payload<>((K)v,delegate.get(v).getValue(),delegate.get(v).getInitializationTime()));
}
delegate.remove(v);
count++;
}
}
}
基於容量的淘汰策略具體實現是:後臺線程先取出當前緩存對象集合的size,如果大於maximum值,將執行淘汰任務。根據緩存對象的lastAccessTime做排序,將“最近使用頻率最低的”(maximum * clearFactor) + size - maximum個對象移除掉。例maximum值爲100,factor爲0.1,當前緩存集合的size爲110,則此次移除任務將移除掉100*0.1+110-100,即20個緩存對象。
ps:上層業務再使用時應基於實際業務需求,合理的設置ttl、maximum、factor及interval等參數。例interval值設置的越小,緩存移除的“實時性”及“準確性”就越高,但是系統的開銷也會更高。