LruMemoryCache解析

import java.util.LinkedHashMap;
import java.util.Map;
//解析参考http://code1.okbase.net/codefile/LruMemoryCache.java_2014121628509_67.htm
/**
 * Created by skyxue on 15/5/29.
 * 内存缓存

 */

  1. **
  2. * A cache that holds strong references to a limited number of Bitmaps. Each time a Bitmap is accessed, it is moved to
  3. * the head of a queue. When a Bitmap is added to a full cache, the Bitmap at the end of that queue is evicted and may
  4. * become eligible for garbage collection.<br />
  5. * <br />
  6. * <b>NOTE:</b> This cache uses only strong references for stored Bitmaps.
  7. * @since 1.8.1
  8. */
//LRU是Least Recently Used 近期最少使用算法

public class LruMemoryCache<K, V> {

    private final LinkedHashMap<K, V> map;

    private int size;
    private int maxSize;

    private int putCount;
    private int createCount;
    private int evictionCount;
    private int hitCount;
    private int missCount;

    private KeyExpiryMap<K, Long> keyExpiryMap;


  1. /**
  2. * @param maxSize Maximum sum of the sizes of the Bitmaps in this cache
  3.  缓存可承受的最大字节数,缓存底部存储结构使用的是LinkedHashMap
  4. */

    public LruMemoryCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        this.maxSize = maxSize;
        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
        this.keyExpiryMap = new KeyExpiryMap<K, Long>(0, 0.75f);
    }

    public void setMaxSize(int maxSize) {
        this.maxSize = maxSize;
        trimToSize(maxSize);
    }


  1. /**
  2. * Returns the Bitmap for {@code key} if it exists in the cache. If a Bitmap was returned, it is moved to the head
  3. * of the queue. This returns null if a Bitmap is not cached.
  4. */

    public final V get(K key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        V mapValue;
        synchronized (this) {
            if (!keyExpiryMap.containsKey(key)) {
                this.remove(key);
                return null;
            }
            mapValue = map.get(key);
            if (mapValue != null) {
                hitCount++;
                return mapValue;
            }
            missCount++;
        }

        V createdValue = create(key);
        if (createdValue == null) {
            return null;
        }

        synchronized (this) {
            createCount++;
            mapValue = map.put(key, createdValue);

            if (mapValue != null) {
                map.put(key, mapValue);
            } else {
                size += safeSizeOf(key, createdValue);
            }
        }

        if (mapValue != null) {
            entryRemoved(false, key, createdValue, mapValue);
            return mapValue;
        } else {
            trimToSize(maxSize);
            return createdValue;
        }
    }


  1. /**
  2. * Caches {@code Bitmap} for {@code key}. The Bitmap is moved to the head of the queue.
  3. */

    public final V put(K key, V value) {
        return put(key, value, Long.MAX_VALUE);
    }


    public final V put(K key, V value, long expiryTimestamp) {
        if (key == null || value == null) {
            throw new NullPointerException("key == null || value == null");
        }

        V previous;
        synchronized (this) {
            putCount++;
            size += safeSizeOf(key, value);
            previous = map.put(key, value);
            keyExpiryMap.put(key, expiryTimestamp);
            if (previous != null) {
                size -= safeSizeOf(key, previous);
            }
        }

        if (previous != null) {
            entryRemoved(false, key, previous, value);
        }

        trimToSize(maxSize);
        return previous;
    }

  1. /**
  2. * Remove the eldest entries until the total of remaining entries is at or below the requested size.
  3. *
  4. * @param maxSize the maximum size of the cache before returning. May be -1 to evict even 0-sized elements.
  5. */

    private void trimToSize(int maxSize) {
        while (true) {
            K key;
            V value;
            synchronized (this) {
                if (size <= maxSize || map.isEmpty()) {
                    break;
                }

                Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
                key = toEvict.getKey();
                value = toEvict.getValue();
                map.remove(key);
                keyExpiryMap.remove(key);
                size -= safeSizeOf(key, value);
                evictionCount++;
            }

            entryRemoved(true, key, value, null);
        }
    }

    public final V remove(K key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        V previous;
        synchronized (this) {
            previous = map.remove(key);
            keyExpiryMap.remove(key);
            if (previous != null) {
                size -= safeSizeOf(key, previous);
            }
        }

        if (previous != null) {
            entryRemoved(false, key, previous, null);
        }

        return previous;
    }

    public final boolean containsKey(K key) {
        return map.containsKey(key);
    }

    protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {
    }


    protected V create(K key) {
        return null;
    }

    private int safeSizeOf(K key, V value) {
        int result = sizeOf(key, value);
        if (result <= 0) {
            size = 0;
            for (Map.Entry<K, V> entry : map.entrySet()) {
                size += sizeOf(entry.getKey(), entry.getValue());
            }
        }
        return result;
    }

    protected int sizeOf(K key, V value) {
        return 1;
    }

    public final void evictAll() {
        trimToSize(-1); // -1 will evict 0-sized elements
        keyExpiryMap.clear();
    }

    public synchronized final int size() {
        return size;
    }

    public synchronized final int maxSize() {
        return maxSize;
    }


    public synchronized final int hitCount() {
        return hitCount;
    }


    public synchronized final int missCount() {
        return missCount;
    }

    public synchronized final int createCount() {
        return createCount;
    }


    public synchronized final int putCount() {
        return putCount;
    }


    public synchronized final int evictionCount() {
        return evictionCount;
    }


    public synchronized final Map<K, V> snapshot() {
        return new LinkedHashMap<K, V>(map);
    }

    public synchronized final String toString() {
        int accesses = hitCount + missCount;
        int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
        return String.format("LruMemoryCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]", maxSize, hitCount, missCount, hitPercent);
    }




}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值