Jodd cache提供了一组cache的实现,其层次如下:
其中,
AbstractCacheMap是一个具有计时和大小的缓存map的默认实现,它的实现类必须:
创建一个新的缓存map。
实现自己的删除(prune)策略。
内部使用ReentranReadWriteLock来同步。因为从一个读锁升级到一个写锁是不可能的,因此在get(Object)方法内要注意。
FIFOCach:先进先出缓存。
优点是简单高效。缺点是不灵活,没有在内存中保存常用的缓存对象。
/**
* Creates a new LRU cache.
*/
public FIFOCache(int cacheSize, long timeout) {
this.cacheSize = cacheSize;
this.timeout = timeout;
cacheMap = new LinkedHashMap<K,CacheObject<K,V>>(cacheSize + 1, 1.0f, false);
}
// ---------------------------------------------------------------- prune
/**
* Prune expired objects and, if cache is still full, the first one.
*/
@Override
protected int pruneCache() {
int count = 0;
CacheObject<K,V> first = null;
Iterator<CacheObject<K,V>> values = cacheMap.values().iterator();
while (values.hasNext()) {
CacheObject<K,V> co = values.next();
if (co.isExpired() == true) {
values.remove();
count++;
}
if (first == null) {
first = co;
}
}
if (isFull()) {
if (first != null) {
cacheMap.remove(first.key);
count++;
}
}
return count;
}LFUCache:最少访问次数缓存。
优点是常用缓存保留在内存中,偶然会使扫描算法失效。缺点是大的获取消耗即这个算法不能快速适应变化的使用模式,特别是集群的临时获取是无效的。
public LFUCache(int maxSize, long timeout) {
this.cacheSize = maxSize;
this.timeout = timeout;
cacheMap = new HashMap<K, CacheObject<K,V>>(maxSize + 1);
}
// ---------------------------------------------------------------- prune
/**
* Prunes expired and, if cache is still full, the LFU element(s) from the cache.
* On LFU removal, access count is normalized to value which had removed object.
* Returns the number of removed objects.
*/
@Override
protected int pruneCache() {
int count = 0;
CacheObject<K,V> comin = null;
// remove expired items and find cached object with minimal access count
Iterator<CacheObject<K,V>> values = cacheMap.values().iterator();
while (values.hasNext()) {
CacheObject<K,V> co = values.next();
if (co.isExpired() == true) {
values.remove();
onRemove(co.key, co.cachedObject);
count++;
continue;
}
if (comin == null) {
comin = co;
} else {
if (co.accessCount < comin.accessCount) {
comin = co;
}
}
}
if (isFull() == false) {
return count;
}
// decrease access count to all cached objects
if (comin != null) {
long minAccessCount = comin.accessCount;
values = cacheMap.values().iterator();
while (values.hasNext()) {
CacheObject<K, V> co = values.next();
co.accessCount -= minAccessCount;
if (co.accessCount <= 0) {
values.remove();
onRemove(co.key, co.cachedObject);
count++;
}
}
}
return count;
}LRUCache:最近未访问缓存。
缓存对象的消耗是一个常量。简单高效,比FIFO更适应一个变化的场景。缺点是可能会被不会重新访问的缓存占满空间,特别是在面对获取类型扫描时则完全不起作用。然后它是目前最常用的缓存算法。
/**
* Creates a new LRU cache.
*/
public LRUCache(int cacheSize, long timeout) {
this.cacheSize = cacheSize;
this.timeout = timeout;
cacheMap = new LinkedHashMap<K, CacheObject<K,V>>(cacheSize + 1, 1.0f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return LRUCache.this.removeEldestEntry(size());
}
};
}
/**
* Removes the eldest entry if current cache size exceed cache size.
*/
protected boolean removeEldestEntry(int currentSize) {
if (cacheSize == 0) {
return false;
}
return currentSize > cacheSize;
}
// ---------------------------------------------------------------- prune
/**
* Prune only expired objects, <code>LinkedHashMap</code> will take care of LRU if needed.
*/
@Override
protected int pruneCache() {
if (isPruneExpiredActive() == false) {
return 0;
}
int count = 0;
Iterator<CacheObject<K,V>> values = cacheMap.values().iterator();
while (values.hasNext()) {
CacheObject<K,V> co = values.next();
if (co.isExpired() == true) {
values.remove();
count++;
}
}
return count;
}TimedCache 不限制大小,只有当对象过期时才会删除。标准的chache方法不会显式的调用删除(prune),而是根据定义好的延迟进行定时删除。
public TimedCache(long timeout) {
this.cacheSize = 0;
this.timeout = timeout;
cacheMap = new HashMap<K, CacheObject<K,V>>();
}
// ---------------------------------------------------------------- prune
/**
* Prunes expired elements from the cache. Returns the number of removed objects.
*/
@Override
protected int pruneCache() {
int count = 0;
Iterator<CacheObject<K,V>> values = cacheMap.values().iterator();
while (values.hasNext()) {
CacheObject co = values.next();
if (co.isExpired() == true) {
values.remove();
count++;
}
}
return count;
}
// ---------------------------------------------------------------- auto prune
protected Timer pruneTimer;
/**
* Schedules prune.
*/
public void schedulePrune(long delay) {
if (pruneTimer != null) {
pruneTimer.cancel();
}
pruneTimer = new Timer();
pruneTimer.schedule(
new TimerTask() {
@Override
public void run() {
prune();
}
}, delay, delay
);
}
/**
* Cancels prune schedules.
*/
public void cancelPruneSchedule() {
if (pruneTimer != null) {
pruneTimer.cancel();
pruneTimer = null;
}
}注意,还提供了一个FileLFUCache,
没有继承AbstractCacheMap.用LFU将文件缓存到内存,极大加快访问常用文件的性能。
protected final LFUCache<File, byte[]> cache;
protected final int maxSize;
protected final int maxFileSize;
protected int usedSize;
/**
* Creates file LFU cache with specified size. Sets
* {@link #maxFileSize max available file size} to half of this value.
*/
public FileLFUCache(int maxSize) {
this(maxSize, maxSize / 2, 0);
}
public FileLFUCache(int maxSize, int maxFileSize) {
this(maxSize, maxFileSize, 0);
}
/**
* Creates new File LFU cache.
* @param maxSize total cache size in bytes
* @param maxFileSize max available file size in bytes, may be 0
* @param timeout timeout, may be 0
*/
public FileLFUCache(int maxSize, int maxFileSize, long timeout) {
this.cache = new LFUCache<File, byte[]>(0, timeout) {
@Override
public boolean isFull() {
return usedSize > FileLFUCache.this.maxSize;
}
@Override
protected void onRemove(File key, byte[] cachedObject) {
usedSize -= cachedObject.length;
}
};
this.maxSize = maxSize;
this.maxFileSize = maxFileSize;
}
// ---------------------------------------------------------------- get
/**
* Returns max cache size in bytes.
*/
public int getMaxSize() {
return maxSize;
}
/**
* Returns actually used size in bytes.
*/
public int getUsedSize() {
return usedSize;
}
/**
* Returns maximum allowed file size that can be added to the cache.
* Files larger than this value will be not added, even if there is
* enough room.
*/
public int getMaxFileSize() {
return maxFileSize;
}
/**
* Returns number of cached files.
*/
public int getCachedFilesCount() {
return cache.size();
}
/**
* Returns timeout.
*/
public long getCacheTimeout() {
return cache.getCacheTimeout();
}
/**
* Clears the cache.
*/
public void clear() {
cache.clear();
usedSize = 0;
}
// ---------------------------------------------------------------- get
public byte[] getFileBytes(String fileName) throws IOException {
return getFileBytes(new File(fileName));
}
/**
* Returns cached file bytes.
*/
public byte[] getFileBytes(File file) throws IOException {
byte[] bytes = cache.get(file);
if (bytes != null) {
return bytes;
}
// add file
bytes = FileUtil.readBytes(file);
if ((maxFileSize != 0) && (file.length() > maxFileSize)) {
// don't cache files that size exceed max allowed file size
return bytes;
}
usedSize += bytes.length;
// put file into cache
// if used size > total, purge() will be invoked
cache.put(file, bytes);
return bytes;
}

本文暂时没有评论,来添加一个吧(●'◡'●)