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;
}

jodd-cache集锦的更多相关文章

  1. jodd cache实现缓存超时

    public class JoddCache { private static final int CACHE_SIZE = 2; private final static Cache<Obje ...

  2. 『奇葩问题集锦』Malformed lock file found: /var/cache/dnf/metadata_lock.pid.

    Malformed lock file found: /var/cache/dnf/metadata_lock.pid.Ensure no other dnf process is running a ...

  3. java jodd轻量级开发框架

    http://git.oschina.net/huangyong/jodd_demo/blob/master/jodd-example/src/main/java/jodd/example/servi ...

  4. 大型互联网架构概述 关于架构的架构目标 典型实现 DNS CDN LB WEB APP SOA MQ CACHE STORAGE

    大型互联网架构概述 目录 架构目标 典型实现 DNS CDN LB WEB APP SOA MQ CACHE STORAGE 本文旨在简单介绍大型互联网的架构和核心组件实现原理. 理论上讲,从安装配置 ...

  5. springboot项目部署到独立tomcat的爬坑集锦

    目录 集锦一:普通的springboot项目直接部署jar包 集锦二:springboot项目不能直接打war包部署 集锦三:因为tomcat版本问题导致的lombok插件报错:Invalid byt ...

  6. bug集锦------持续但不定期 更新

    对于个人而言:这个错误集锦是很有必要的. 为了避免误导他人,其中个人想法:用 紫色加粗 标注. 1.springboot端口冲突: Protocol handler start failed2.spr ...

  7. 13 Zabbix4.4.1系统告警“More than 75% used in the configuration cache”

    点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 13 Zabbix4.4.1系统告警“More than 75% used in the conf ...

  8. Jodd - Java界的瑞士军刀轻量级工具包!

    Jodd介绍 Jodd是对于Java开发更便捷的开源迷你框架,包含工具类.实用功能的集合,总包体积不到1.7M. Jodd构建于通用场景使开发变得简单,但Jodd并不简单!它能让你把事情做得更好,实现 ...

  9. Redis面试题集锦(精选)

    1.什么是 Redis?简述它的优缺点? Redis的全称是:Remote Dictionary.Server,本质上是一个Key-Value 类型的内存数据库,很像memcached,整个数据库统统 ...

随机推荐

  1. [Recompose] Merge RxJS Button Event Streams to Build a React Counter Component

    Combining input streams then using scan to track the results is a common scenario when coding with s ...

  2. 【POJ 2195】 Going Home(KM算法求最小权匹配)

    [POJ 2195] Going Home(KM算法求最小权匹配) Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submiss ...

  3. quartz-misfire 错失、补偿执行

    调度(scheduleJob)或恢复调度(resumeTrigger,resumeJob)后不同的misfire对应的处理规则 misfire产生的条件是:到了该触发执行时上一个执行还未完成,且线程池 ...

  4. Controller接口控制器

    1.Controller简介 Controller控制器,是MVC中的部分C,为什么是部分呢?因为此处的控制器主要负责功能处理部分: 1.收集.验证请求参数并绑定到命令对象: 2.将命令对象交给业务对 ...

  5. Python正则表达式初识(二)

    前几天给大家分享了Python正则表达式初识(一),介绍了正则表达式中的三个特殊字符“^”.“.”和“*”,感兴趣的伙伴可以戳进去看看,今天小编继续给大家分享Python正则表达式相关特殊字符知识点. ...

  6. React开发实时聊天招聘工具 -第三章 React基础知识回顾

    function a (props) { return <h1>hello world{this.props.asd}</h1> } class a extends React ...

  7. js中split,splice,slice方法之间的差异。

    首先我们先来林格斯双击翻译一下: split  劈开, 使分裂: splice   接合; 使结合: slice  切成薄片, 切: 我先是这么区分的:这三个方法最后一个字母是t的是字符串方法,是e的 ...

  8. Hexo Daemon

    前提 今天中午的时候发现自已网站突然不能访问了,我猜肯定是后台的hexo服务异常自动kill掉了.果然登录服务器ps -ef | grep hexo查看进程,果然发现hexo的进程不在了.由于我将输出 ...

  9. Java基础关于Map(字典)的方法使用

    Java基础关于Map(字典)的方法使用 java中一般用map与hashmap来创建一个key-value对象 使用前提是要导入方法包: import java.util.HashMap: impo ...

  10. 【editplus经常用的快捷键】Editplus 选中一行ctrl+r,Edit 合并行 Ctrl+Shift+J 合并选定行 删除当前行

    Editplus 选中一行: ctrl+rEditplus 复制一行: ctrl+r选择行,然后ctrl+c复制.复制一行到下一行中:Editplus有:Ctrl+j 复制上一行的一个字符到当前行Ed ...