zoukankan      html  css  js  c++  java
  • Android提供的LruCache类简介[转载]

    转自:here

      1 package android.util;  
      2   
      3 import java.util.LinkedHashMap;  
      4 import java.util.Map;  
      5   
      6 /** 
      7  * A cache that holds strong references to a limited number of values. Each time 
      8  * a value is accessed, it is moved to the head of a queue. When a value is 
      9  * added to a full cache, the value at the end of that queue is evicted and may 
     10  * become eligible for garbage collection. 
     11  * Cache保存一个强引用来限制内容数量,每当Item被访问的时候,此Item就会移动到队列的头部。
     12  * 当cache已满的时候加入新的item时,在队列尾部的item会被回收。
     13  * <p>If your cached values hold resources that need to be explicitly released, 
     14  * override {@link #entryRemoved}. 
     15  * 如果你cache的某个值需要明确释放,重写entryRemoved()
     16  * <p>If a cache miss should be computed on demand for the corresponding keys, 
     17  * override {@link #create}. This simplifies the calling code, allowing it to 
     18  * assume a value will always be returned, even when there's a cache miss. 
     19  * 如果key相对应的item丢掉啦,重写create().这简化了调用代码,即使丢失了也总会返回。
     20  * <p>By default, the cache size is measured in the number of entries. Override 
     21  * {@link #sizeOf} to size the cache in different units. For example, this cache 
     22  * is limited to 4MiB of bitmaps: 默认cache大小是测量的item的数量,重写sizeof计算不同item的
     23  *  大小。
     24  * <pre>   {@code 
     25  *   int cacheSize = 4 * 1024 * 1024; // 4MiB 
     26  *   LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) { 
     27  *       protected int sizeOf(String key, Bitmap value) { 
     28  *           return value.getByteCount(); 
     29  *       } 
     30  *   }}</pre> 
     31  * 
     32  * <p>This class is thread-safe. Perform multiple cache operations atomically by 
     33  * synchronizing on the cache: <pre>   {@code 
     34  *   synchronized (cache) { 
     35  *     if (cache.get(key) == null) { 
     36  *         cache.put(key, value); 
     37  *     } 
     38  *   }}</pre> 
     39  * 
     40  * <p>This class does not allow null to be used as a key or value. A return 
     41  * value of null from {@link #get}, {@link #put} or {@link #remove} is 
     42  * unambiguous: the key was not in the cache.
     43  * 不允许key或者value为null
     44  *  当get(),put(),remove()返回值为null时,key相应的项不在cache中
     45  */  
     46 public class LruCache<K, V> {  
     47     private final LinkedHashMap<K, V> map;  
     48   
     49     /** Size of this cache in units. Not necessarily the number of elements. */  
     50     private int size; //已经存储的大小
     51     private int maxSize; //规定的最大存储空间
     52   
     53     private int putCount;  //put的次数
     54     private int createCount;  //create的次数
     55     private int evictionCount;  //回收的次数
     56     private int hitCount;  //命中的次数
     57     private int missCount;  //丢失的次数
     58   
     59     /** 
     60      * @param maxSize for caches that do not override {@link #sizeOf}, this is 
     61      *     the maximum number of entries in the cache. For all other caches, 
     62      *     this is the maximum sum of the sizes of the entries in this cache. 
     63      */  
     64     public LruCache(int maxSize) {  
     65         if (maxSize <= 0) {  
     66             throw new IllegalArgumentException("maxSize <= 0");  
     67         }  
     68         this.maxSize = maxSize;  
     69         this.map = new LinkedHashMap<K, V>(0, 0.75f, true);  
     70     }  
     71   
     72     /** 
     73      * Returns the value for {@code key} if it exists in the cache or can be 
     74      * created by {@code #create}. If a value was returned, it is moved to the 
     75      * head of the queue. This returns null if a value is not cached and cannot 
     76      * be created. 通过key返回相应的item,或者创建返回相应的item。相应的item会移动到队列的头部,
     77      * 如果item的value没有被cache或者不能被创建,则返回null。
     78      */  
     79     public final V get(K key) {  
     80         if (key == null) {  
     81             throw new NullPointerException("key == null");  
     82         }  
     83   
     84         V mapValue;  
     85         synchronized (this) {  
     86             mapValue = map.get(key);  
     87             if (mapValue != null) {  
     88                 hitCount++;  //命中
     89                 return mapValue;  
     90             }  
     91             missCount++;  //丢失
     92         }  
     93   
     94         /* 
     95          * Attempt to create a value. This may take a long time, and the map 
     96          * may be different when create() returns. If a conflicting value was 
     97          * added to the map while create() was working, we leave that value in 
     98          * the map and release the created value. 
     99          * 如果丢失了就试图创建一个item
    100          */  
    101   
    102         V createdValue = create(key);  
    103         if (createdValue == null) {  
    104             return null;  
    105         }  
    106   
    107         synchronized (this) {  
    108             createCount++;//创建++  
    109             mapValue = map.put(key, createdValue);  
    110   
    111             if (mapValue != null) {  
    112                 // There was a conflict so undo that last put  
    113                 //如果前面存在oldValue,那么撤销put() 
    114                 map.put(key, mapValue);  
    115             } else {  
    116                 size += safeSizeOf(key, createdValue);  
    117             }  
    118         }  
    119   
    120         if (mapValue != null) {  
    121             entryRemoved(false, key, createdValue, mapValue);  
    122             return mapValue;  
    123         } else {  
    124             trimToSize(maxSize);  
    125             return createdValue;  
    126         }  
    127     }  
    128   
    129     /** 
    130      * Caches {@code value} for {@code key}. The value is moved to the head of 
    131      * the queue. 
    132      * 
    133      * @return the previous value mapped by {@code key}. 
    134      */  
    135     public final V put(K key, V value) {  
    136         if (key == null || value == null) {  
    137             throw new NullPointerException("key == null || value == null");  
    138         }  
    139   
    140         V previous;  
    141         synchronized (this) {  
    142             putCount++;  
    143             size += safeSizeOf(key, value);  
    144             previous = map.put(key, value);  
    145             if (previous != null) {  //返回的先前的value值
    146                 size -= safeSizeOf(key, previous);  
    147             }  
    148         }  
    149   
    150         if (previous != null) {  
    151             entryRemoved(false, key, previous, value);  
    152         }  
    153   
    154         trimToSize(maxSize);  
    155         return previous;  
    156     }  
    157   
    158     /** 
    159      * @param maxSize the maximum size of the cache before returning. May be -1 
    160      *     to evict even 0-sized elements. 
    161      *  清空cache空间
    162      */  
    163     private void trimToSize(int maxSize) {  
    164         while (true) {  
    165             K key;  
    166             V value;  
    167             synchronized (this) {  
    168                 if (size < 0 || (map.isEmpty() && size != 0)) {  
    169                     throw new IllegalStateException(getClass().getName()  
    170                             + ".sizeOf() is reporting inconsistent results!");  
    171                 }  
    172   
    173                 if (size <= maxSize) {  
    174                     break;  
    175                 }  
    176   
    177                 Map.Entry<K, V> toEvict = map.eldest();  
    178                 if (toEvict == null) {  
    179                     break;  
    180                 }  
    181   
    182                 key = toEvict.getKey();  
    183                 value = toEvict.getValue();  
    184                 map.remove(key);  
    185                 size -= safeSizeOf(key, value);  
    186                 evictionCount++;  
    187             }  
    188   
    189             entryRemoved(true, key, value, null);  
    190         }  
    191     }  
    192   
    193     /** 
    194      * Removes the entry for {@code key} if it exists. 
    195      * 删除key相应的cache项,返回相应的value
    196      * @return the previous value mapped by {@code key}. 
    197      */  
    198     public final V remove(K key) {  
    199         if (key == null) {  
    200             throw new NullPointerException("key == null");  
    201         }  
    202   
    203         V previous;  
    204         synchronized (this) {  
    205             previous = map.remove(key);  
    206             if (previous != null) {  
    207                 size -= safeSizeOf(key, previous);  
    208             }  
    209         }  
    210   
    211         if (previous != null) {  
    212             entryRemoved(false, key, previous, null);  
    213         }  
    214   
    215         return previous;  
    216     }  
    217   
    218     /** 
    219      * Called for entries that have been evicted or removed. This method is 
    220      * invoked when a value is evicted to make space, removed by a call to 
    221      * {@link #remove}, or replaced by a call to {@link #put}. The default 
    222      * implementation does nothing. 
    223      * 当item被回收或者删掉时调用。改方法当value被回收释放存储空间时被remove调用,
    224      * 或者替换item值时put调用,默认实现什么都没做。
    225      * <p>The method is called without synchronization: other threads may 
    226      * access the cache while this method is executing. 
    227      * 
    228      * @param evicted true if the entry is being removed to make space, false 
    229      *     if the removal was caused by a {@link #put} or {@link #remove}. 
    230      * true---为释放空间被删除;false---put或remove导致
    231      * @param newValue the new value for {@code key}, if it exists. If non-null, 
    232      *     this removal was caused by a {@link #put}. Otherwise it was caused by 
    233      *     an eviction or a {@link #remove}. 
    234      */  
    235     protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}  
    236   
    237     /** 
    238      * Called after a cache miss to compute a value for the corresponding key. 
    239      * Returns the computed value or null if no value can be computed. The 
    240      * default implementation returns null. 
    241      * 当某Item丢失时会调用到,返回计算的相应的value或者null
    242      * <p>The method is called without synchronization: other threads may 
    243      * access the cache while this method is executing. 
    244      * 
    245      * <p>If a value for {@code key} exists in the cache when this method 
    246      * returns, the created value will be released with {@link #entryRemoved} 
    247      * and discarded. This can occur when multiple threads request the same key 
    248      * at the same time (causing multiple values to be created), or when one 
    249      * thread calls {@link #put} while another is creating a value for the same 
    250      * key. 
    251      */  
    252     protected V create(K key) {  
    253         return null;  
    254     }  
    255   
    256     private int safeSizeOf(K key, V value) {  
    257         int result = sizeOf(key, value);  
    258         if (result < 0) {  
    259             throw new IllegalStateException("Negative size: " + key + "=" + value);  
    260         }  
    261         return result;  
    262     }  
    263   
    264     /** 
    265      * Returns the size of the entry for {@code key} and {@code value} in 
    266      * user-defined units.  The default implementation returns 1 so that size 
    267      * is the number of entries and max size is the maximum number of entries. 
    268      * 返回用户定义的item的大小,默认返回1代表item的数量,最大size就是最大item值
    269      * <p>An entry's size must not change while it is in the cache. 
    270      */  
    271     protected int sizeOf(K key, V value) {  
    272         return 1;  
    273     }  
    274   
    275     /** 
    276      * Clear the cache, calling {@link #entryRemoved} on each removed entry. 
    277      * 清空cacke
    278      */  
    279     public final void evictAll() {  
    280         trimToSize(-1); // -1 will evict 0-sized elements  
    281     }  
    282   
    283     /** 
    284      * For caches that do not override {@link #sizeOf}, this returns the number 
    285      * of entries in the cache. For all other caches, this returns the sum of 
    286      * the sizes of the entries in this cache. 
    287      */  
    288     public synchronized final int size() {  
    289         return size;  
    290     }  
    291   
    292     /** 
    293      * For caches that do not override {@link #sizeOf}, this returns the maximum 
    294      * number of entries in the cache. For all other caches, this returns the 
    295      * maximum sum of the sizes of the entries in this cache. 
    296      */  
    297     public synchronized final int maxSize() {  
    298         return maxSize;  
    299     }  
    300   
    301     /** 
    302      * Returns the number of times {@link #get} returned a value that was 
    303      * already present in the cache. 
    304      */  
    305     public synchronized final int hitCount() {  
    306         return hitCount;  
    307     }  
    308   
    309     /** 
    310      * Returns the number of times {@link #get} returned null or required a new 
    311      * value to be created. 
    312      */  
    313     public synchronized final int missCount() {  
    314         return missCount;  
    315     }  
    316   
    317     /** 
    318      * Returns the number of times {@link #create(Object)} returned a value. 
    319      */  
    320     public synchronized final int createCount() {  
    321         return createCount;  
    322     }  
    323   
    324     /** 
    325      * Returns the number of times {@link #put} was called. 
    326      */  
    327     public synchronized final int putCount() {  
    328         return putCount;  
    329     }  
    330   
    331     /** 
    332      * Returns the number of values that have been evicted. 
    333      * 返回被回收的数量
    334      */  
    335     public synchronized final int evictionCount() {  
    336         return evictionCount;  
    337     }  
    338   
    339     /** 
    340      * Returns a copy of the current contents of the cache, ordered from least 
    341      * recently accessed to most recently accessed. 返回当前cache的副本,从最近最少访问到最多访问
    342      */  
    343     public synchronized final Map<K, V> snapshot() {  
    344         return new LinkedHashMap<K, V>(map);  
    345     }  
    346   
    347     @Override public synchronized final String toString() {  
    348         int accesses = hitCount + missCount;  
    349         int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;  
    350         return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",  
    351                 maxSize, hitCount, missCount, hitPercent);  
    352     }  
    353 }  
  • 相关阅读:
    Leetcode 92. Reverse Linked List II
    Leetcode 206. Reverse Linked List
    Leetcode 763. Partition Labels
    Leetcode 746. Min Cost Climbing Stairs
    Leetcode 759. Employee Free Time
    Leetcode 763. Partition Labels
    搭建数据仓库第09篇:物理建模
    Python进阶篇:Socket多线程
    Python进阶篇:文件系统的操作
    搭建数据仓库第08篇:逻辑建模–5–维度建模核心之一致性维度2
  • 原文地址:https://www.cnblogs.com/wangziqiang/p/3873411.html
Copyright © 2011-2022 走看看