编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

jodd-cache集锦(jet cache)

wxchong 2024-08-02 08:52:49 开源技术 13 ℃ 0 评论

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

Tags:

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

欢迎 发表评论:

最近发表
标签列表