LRUCache

  1. 概述
    LruCache是一个泛型类,它内部采用一个LinkedHashMap以强引用的方式储存外界的缓存对象,为其提供了get和put方法来完成缓存的获取和添加操作。 当缓存存满时,LruCache会移除较早使用的缓存对象, 然后再添加新的缓存对象。

  2. 构造方法

 /** Size of this cache in units. Not necessarily the number of elements. */
    private int size; //当前缓存大小
    private int maxSize; //最大缓存大小

    private int putCount;  //put的次数(为LruCache添加缓存对象的次数)
    private int createCount; // create的次数
    private int evictionCount; //回收的次数
    private int hitCount; //命中缓存次数
    private int missCount; // 未命中次数

    /**
     * @param maxSize for caches that do not override {@link #sizeOf}, this is
     *     the maximum number of entries in the cache. For all other caches,
     *     this is the maximum sum of the sizes of the entries in this cache.
     */
    public LruCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        this.maxSize = maxSize;
        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
    }

例子

int maxMemory = (int) (Runtime.getRuntime().maxMemory())/1024;//获取可用内存,转换为单位KB
      int maxCache = maxMemory/10;//缓存大小为可用内存的1/10
      LruCache mMemoryCache = new LruCache<String,Bitmap>(maxCache){
          @Override//重写sizeOf方法,返回每条数据占用的内存
          protected int sizeOf(String key, Bitmap value) {
              return value.getRowBytes()*value.getHeight() / 1024;
              //return value.getByteCount() / 1024;
          }
      };

这里sizeOf和 maxMemory要统一单位, 用于计算对象大小。

2. get()

public final V get(K key) {
        if (key == null) {//如果key为null,抛出异常
            throw new NullPointerException("key == null");
        }

        V mapValue;
        synchronized (this) {
            mapValue = map.get(key); // 读取key对应的value
            if (mapValue != null) {
                hitCount++;
                return mapValue; //如果获取到当前内容则返回
            }
            missCount++;
        }

        /*
         * Attempt to create a value. This may take a long time, and the map
         * may be different when create() returns. If a conflicting value was
         * added to the map while create() was working, we leave that value in
         * the map and release the created value.
         */
         //尝试创建value,可能会消耗一定的时间,当创建完成时,map可能已经发生变化如果此时发现创建时使用的key已经存在,导致冲突,丢弃掉create创建的值

如果未获取到value,调用create方法,尝试创建对象
//也可以重写此方法。决定获取不到的时候该添加什么。
        V createdValue = create(key);
        if (createdValue == null) {
            return null;
        }
 //以下部分为创建之后对map的修改动作,包括存放对象,调整size等。
        synchronized (this) {
            createCount++;
            mapValue = map.put(key, createdValue);

            if (mapValue != null) {
                // There was a conflict so undo that last put
                map.put(key, mapValue);
            } else {
                size += safeSizeOf(key, createdValue);
            }
        }

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

3. put

 /**
     * Caches {@code value} for {@code key}. The value is moved to the head of
     * the queue.
     *
     * @return the previous value mapped by {@code key}.
     * 将keyvalue移到队列头部
     */
    public final V put(K key, V value) {
        if (key == null || value == null) {
            throw new NullPointerException("key == null || value == null");
            //不允许空key或者空value
        }

        V previous;
        synchronized (this) {
            putCount++;
            size += safeSizeOf(key, value); //size加上占用的空间
            previous = map.put(key, value);//linkedHashMap.put操作
            if (previous != null) {
            //如果之前的key已经有对应的值了 减少size
                size -= safeSizeOf(key, previous);
            }
        }

        if (previous != null) {
        //并且移除
            entryRemoved(false, key, previous, value);//空方法 可以进行一些资源回收的操作。
        }

        trimToSize(maxSize);
        return previous;
    }
//size必须大于1;
private int safeSizeOf(K key, V value) {
        int result = sizeOf(key, value);
        if (result < 0) {
            throw new IllegalStateException("Negative size: " + key + "=" + value);
        }
        return result;
    }

    /**
     * Returns the size of the entry for {@code key} and {@code value} in
     * user-defined units.  The default implementation returns 1 so that size
     * is the number of entries and max size is the maximum number of entries.
     *
     * <p>An entry's size must not change while it is in the cache.
     */
     //用户自定义
    protected int sizeOf(K key, V value) {
        return 1;
    }

4. trimToSize

/**
     * Remove the eldest entries until the total of remaining entries is at or
     * below the requested size.
     *
     * @param maxSize the maximum size of the cache before returning. May be -1
     *            to evict even 0-sized elements.
     */
    public void trimToSize(int maxSize) {
        while (true) {
            K key;
            V value;
            synchronized (this) {
                if (size < 0 || (map.isEmpty() && size != 0)) {
                    throw new IllegalStateException(getClass().getName()
                            + ".sizeOf() is reporting inconsistent results!");
                }

                if (size <= maxSize) {
                    break;
                }

                Map.Entry<K, V> toEvict = map.eldest();
                if (toEvict == null) {
                    break;
                }

                key = toEvict.getKey();
                value = toEvict.getValue();
                map.remove(key);
                size -= safeSizeOf(key, value);
                evictionCount++;
            }

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

在缓存将要满之前,删除最近最少访问的对象,即移除掉map的表头元素

5.remove

  public final V remove(K key) {
        if (key == null) { //不允许空键
            throw new NullPointerException("key == null");
        }
        V previous;
        synchronized (this) {
            previous = map.remove(key);
            if (previous != null) { //如果存在key,则返回value,更新size;否则没有找到匹配的key,则返回null
                size -= safeSizeOf(key, previous);
            }
        }
        if (previous != null) {
            entryRemoved(false, key, previous, null); //空方法
        }
        return previous;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值