LRUCache源码解析

package com.example.helloworld;  
  
import java.util.LinkedHashMap;  
import java.util.Map;  
  
/** 
 * Cache保存一个强引用来限制内容数量,每当Item被访问的时候,此Item就会移动到队列的头部。
 * 当cache已满的时候加入新的item时,在队列尾部的item会被回收。
 * 
 * 如果你cache的某个值需要明确释放,重写entryRemoved()
 *  
 * 如果key相对应的item丢掉啦,重写create().这简化了调用代码,即使丢失了也总会返回。
 * 
 * 默认cache大小是测量的item的数量,重写sizeof计算不同item的大小。
 * 
 *   int cacheSize = 4 * 1024 * 1024; // 4MiB 
 *   LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) { 
 *       protected int sizeOf(String key, Bitmap value) { 
 *           return value.getByteCount(); 
 *       } 
 *   }
 * 
 * 这个类是安全的,并发操作时有同步块控制
 * This class is thread-safe. Perform multiple cache operations atomically by 
 * synchronizing on the cache:    
 * 
 *   synchronized (cache) { 
 *     if (cache.get(key) == null) { 
 *         cache.put(key, value); 
 *     } 
 *   } 
 * 
 * ·不允许key或者value为null
 *  当get(),put(),remove()返回值为null时,key相应的项不在cache中
 *  
 *  最少最近使用算法
 */ 
public class LruCache<K, V> {  
	
    private final LinkedHashMap<K, V> map; //LruCache 本质上是一个map  
  
    /** Size of this cache in units. Not necessarily the number of elements. */  
    private int size; 			//已经存储的大小
    private int maxSize; 		//规定的最大存储空间
    private int putCount;       //put的次数
    private int createCount;    //create的次数
    private int evictionCount;  //回收的次数
    private int hitCount;  		//命中的次数
    private int missCount;      //丢失的次数
  
    
    /** 
     * maxSize规定了缓存的最大值,缓存实体的最大值不能超过maxSize
     */  
    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);  
    }  
  
    
    
    /** 
     * 通过key返回相应的item,或者创建返回相应的item。
     * 相应的item会移动到队列的头部,
     * 如果item的value没有被cache或者不能被创建,则返回null。
     */  
    public final V get(K key) {  
     
    	if (key == null) {  
            throw new NullPointerException("key == null");  
        }  
  
        V mapValue;  
        synchronized (this) {  
            mapValue = map.get(key);  
            if (mapValue != null) {  
                hitCount++;  		//命中
                return mapValue;  
            }  
            missCount++; 		 //丢失
        }  
  
        
        /* 
         *  根据key没找到item -->就试图创建一个item 
         *  实际中 create()一般由我们来实现。  LruCache的create()方法默认返回null
         */  
  
        V createdValue = create(key);      
        if (createdValue == null) {  
            return null;  
        }  
  
        synchronized (this) {  
            createCount++;			//创建++  
            mapValue = map.put(key, createdValue);  
  
            if (mapValue != null) {  
                // There was a conflict so undo that last put  
                //如果前面存在oldValue,那么撤销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;  
        }
        
    }  


    
    
    /** 
     * 存入元素--> 刚存入的元素在最前面 
     * 返回值:先前存的值  之前没有值返回null
     */  
    
    public final V put(K key, V value) {  
        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);   //map-->linkedHashMap
            if (previous != null) {  		  //返回的先前的value值
                size -= safeSizeOf(key, previous);  
            }  
        }  
  
        if (previous != null) {               
            entryRemoved(false, key, previous, value); //当新值替换原来的值时调用的方法  默认实现为空  
        }  
  
        trimToSize(maxSize);                 //重新缓存区计算大小
        return previous;  
    }  
  
    /** 
     * @param maxSize the maximum size of the cache before returning. May be -1 
     *     to evict even 0-sized elements. 
     *   清空cache空间 
     */  
    private 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);  
        }  
    }  
  
    /** 
     * Removes the entry for {@code key} if it exists. 
     * 删除key相应的cache项,返回相应的value
     * @return the previous value mapped by {@code key}. 
     */  
    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) {  
                size -= safeSizeOf(key, previous);  
            }  
        }  
  
        if (previous != null) {  
            entryRemoved(false, key, previous, null);  
        }  
  
        return previous;  
    }  
  
    /** 
     * 当item被回收或者删掉时调用。
     * 改方法当value被回收释放存储空间时被remove调用,
     * 或者替换item值时put调用,默认实现什么都没做。
     * 
     * 这个方法没有同步 当这个方法执行时 其他线程可以访问缓存
     * 
     * true---为释放空间被删除;
     * 
     * false---put或remove导致
     * @param newValue the new value for  key, if it exists. If non-null, 
     *     this removal was caused by a  put. Otherwise it was caused by 
     *     an eviction or a remove. 
     *     
     */  
    protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}  
  
    /** 
     * 用户自己实现 
     * 当某Item丢失时会调用到,返回计算的相应的value或者null
     * 这个方法没有同步 当这个方法执行时 其他线程可以访问缓存
     */  
    protected V create(K key) {  
        return null;  
    }  
  
    //检查size 是否合理
    private int safeSizeOf(K key, V value) {  
        int result = sizeOf(key, value);  
        if (result < 0) {  
            throw new IllegalStateException("Negative size: " + key + "=" + value);  
        }  
        return result;  
    }  
  
    /** 
     * 返回用户定义的item的大小,默认返回1代表item的数量,最大size就是最大item值
     * 一般用户自己实现
     */  
    protected int sizeOf(K key, V value) {  
        return 1;  
    }  
  
    
    
    /** 
     * Clear the cache, calling entryRemoved on each removed entry. 
     * 清空cacke
     */  
    public final void evictAll() {  
        trimToSize(-1); 	// -1 will evict 0-sized elements  
    }  
  
    /** 
     * For caches that do not override {@link #sizeOf}, this returns the number 
     * of entries in the cache. For all other caches, this returns the sum of 
     * the sizes of the entries in this cache. 
     * 
     * 返回 缓存中集合的数量  final类型  不允许重写
     */  
    public synchronized final int size() {  
        return size;  
    }  
  
    /** 
     * For caches that do not override {@link #sizeOf}, this returns the maximum 
     * number of entries in the cache. For all other caches, this returns the 
     * maximum sum of the sizes of the entries in this cache. 
     */  
    public synchronized final int maxSize() {  
        return maxSize;  
    }  
  
    
    /** 
     * Returns the number of times {@link #get} returned a value that was 
     * already present in the cache. 
     */  
    public synchronized final int hitCount() {  
        return hitCount;  
    }  
  
    
    /** 
     * Returns the number of times {@link #get} returned null or required a new 
     * value to be created. 
     */  
    public synchronized final int missCount() {  
        return missCount;  
    }  
  
    /** 
     * Returns the number of times {@link #create(Object)} returned a value. 
     */  
    public synchronized final int createCount() {  
        return createCount;  
    }  
  
    
    /** 
     * Returns the number of times {@link #put} was called. 
     */  
    public synchronized final int putCount() {  
        return putCount;  
    }  
  
    /** 
     * Returns the number of values that have been evicted. 
     * 返回被回收的数量
     */  
    public synchronized final int evictionCount() {  
        return evictionCount;  
    }  
  
    /** 
     * Returns a copy of the current contents of the cache, ordered from least 
     * recently accessed to most recently accessed. 返回当前cache的副本,从最近最少访问到最多访问
     */  
    public synchronized final Map<K, V> snapshot() {  
        return new LinkedHashMap<K, V>(map);  
    }  
  
    @Override 
    public synchronized final String toString() {  
        int accesses = hitCount + missCount;  
        int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;  
        return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",  
                maxSize, hitCount, missCount, hitPercent);  
    }
    
    
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值