jodd-cache集锦

Jodd cache提供了一组cache的实现,其层次如下:

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

    }

 

你可能感兴趣的:(cache)