Lrucache源码分析

LruCache源码分析

1. Lrucache封装了LinkedHashMap,并将LinkedHashMap的accessOrder设为true。 可以使遍历顺序和访问顺序一致,其 内部双向链表将会按照近期最少访问到近期最多访问的顺序排列Entry对象 ,这可以用来做缓存。
2.LruCache通过trimToSize方法自动删除最近最少访问的键值对;
3.LruCache不允许空键值;
4.LruCache线程安全;
5.继承LruCache时,必须要复写sizeof方法,用于计算每个条目的大小。

    
    
  1. /*
  2. * Copyright (C) 2011 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package android.support.v4.util;
  17. import java.util.LinkedHashMap;
  18. import java.util.Map;
  19. /**
  20. * Static library version of {@link android.util.LruCache}. Used to write apps
  21. * that run on API levels prior to 12. When running on API level 12 or above,
  22. * this implementation is still used; it does not try to switch to the
  23. * framework's implementation. See the framework SDK documentation for a class
  24. * overview.
  25. */
  26. public class LruCache<K, V> {
  27. private final LinkedHashMap<K, V> map;
  28. /** Size of this cache in units. Not necessarily the number of elements. */
  29. private int size; // 当前的size
  30. private int maxSize; // 最大size
  31. private int putCount; // put的次数
  32. private int createCount; // create的次数
  33. private int evictionCount; // trimToSize中每成功回收一个entry,就会使此值加1
  34. private int hitCount; // hit的次数
  35. private int missCount; // miss的次数
  36. /**
  37. * @param maxSize for caches that do not override {@link #sizeOf}, this is
  38. * the maximum number of entries in the cache. For all other caches,
  39. * this is the maximum sum of the sizes of the entries in this cache.
  40. */
  41. public LruCache(int maxSize) {
  42. if (maxSize <= 0) {
  43. throw new IllegalArgumentException("maxSize <= 0");
  44. }
  45. this.maxSize = maxSize;
  46. this.map = new LinkedHashMap<K, V>(0, 0.75f, true); // 创建LinkedHashMap, 并设置accessOrder为true.
  47. }
  48. /**
  49. * Sets the size of the cache.
  50. * 重新设置该cache的maxSize值
  51. * @param maxSize The new maximum size.
  52. */
  53. public void resize(int maxSize) {
  54. if (maxSize <= 0) {
  55. throw new IllegalArgumentException("maxSize <= 0");
  56. }
  57. synchronized (this) {
  58. this.maxSize = maxSize;
  59. }
  60. trimToSize(maxSize); // 调用trimToSize()清除一些cache来使得当前缓存大小不大于maxSize.
  61. }
  62. /**
  63. * Returns the value for {@code key} if it exists in the cache or can be
  64. * created by {@code #create}. If a value was returned, it is moved to the
  65. * head of the queue. This returns null if a value is not cached and cannot
  66. * be created.
  67.      * 从cache中根据key获取数据
  68. */
  69. public final V get(K key) {
  70. if (key == null) { //key值不能为null.
  71. throw new NullPointerException("key == null");
  72. }
  73. V mapValue;
  74. synchronized (this) {
  75. mapValue = map.get(key); // 从map中获取值
  76. if (mapValue != null) {
  77. hitCount++; // 值不为null则命中加1
  78. return mapValue; // 返回获取的值
  79. }
  80. missCount++; // mapValue为null, miss加1
  81. }
  82. /*
  83. * Attempt to create a value. This may take a long time, and the map
  84. * may be different when create() returns. If a conflicting value was
  85. * added to the map while create() was working, we leave that value in
  86. * the map and release the created value.
  87. */
  88. V createdValue = create(key); // 调用create()方法创建key对应的值,默认返回null, create方法可以重写.应该是为了创建一个默认值
  89. if (createdValue == null) {
  90. return null;
  91. }
  92. // 由于create方法在执行时没有进行同步, 所以不是线程安全的, 这会引发这样一个情况:当create方法在执行时, 有可能在别处又调用了put(key, value)方法, 使得该key有了对应的值
  93. // 然后当你执行下面的代码就会产生了冲突, 具体表现就是mapValue的值不为null.下面就是用来处理这种情况的.并且加入了锁避免再次引发冲突.
  94. synchronized (this) {
  95. createCount++; // create加1
  96. mapValue = map.put(key, createdValue); // 将key和创建的value存入map中
  97. if (mapValue != null) {
  98. // There was a conflict so undo that last put
  99. map.put(key, mapValue); // 如果产生了冲突, 即key对应了一个值,则使用原值覆盖create的值的方法来撤销第109行的put操作
  100. } else {
  101. size += safeSizeOf(key, createdValue); // 没有产生冲突, 即将key和createValue的大小加到当前大小size中.
  102. }
  103. }
  104. if (mapValue != null) {
  105. entryRemoved(false, key, createdValue, mapValue); // 因为覆盖了createValue, 所以相当于remove了createValue, 调用entryRemoved方法
  106. return mapValue;
  107. } else {
  108. trimToSize(maxSize); // 调用trimToSize()清除一些cache来使得当前缓存大小不大于maxSize. 如果当前缓存大小本来就不大于maxSize就直接break不做操作.
  109. return createdValue;
  110. }
  111. }
  112. /**
  113. * Caches {@code value} for {@code key}. The value is moved to the head of
  114. * the queue.
  115. * 向缓存中放置数据.
  116. * @return the previous value mapped by {@code key}.
  117. */
  118. public final V put(K key, V value) {
  119. if (key == null || value == null) { // key和value不能为null.
  120. throw new NullPointerException("key == null || value == null");
  121. }
  122. V previous;
  123. synchronized (this) {
  124. putCount++; // putCount的值加1
  125. size += safeSizeOf(key, value); // 将要插入map中的数据的大小加到size中
  126. previous = map.put(key, value); // 将数据插入到map中
  127. if (previous != null) {
  128. size -= safeSizeOf(key, previous); // 如果key已经对应了一个值则将原值对应的大小从当前的大小中减去
  129. }
  130. }
  131. if (previous != null) {
  132. entryRemoved(false, key, previous, value); // 覆盖了key在缓存中对应的原来的值, 相当于将原来的值remove了, 所以调用entryRemoved方法
  133. }
  134. trimToSize(maxSize); // 调用trimToSize()清除一些cache来使得当前缓存大小不大于maxSize. 如果当前缓存大小本来就不大于maxSize就直接break不做操作.
  135. return previous;
  136. }
  137. /**
  138. * Remove the eldest entries until the total of remaining entries is at or
  139. * below the requested size.
  140. * 清除cache(LinkedHashMap的accessOrder为true时,它里面存储的数据就是按照最近最少到最近最多的排序方式排好了)中的最近最少使用的数据remove, 直到当前的size不大于maxSize为止
  141. * @param maxSize the maximum size of the cache before returning. May be -1
  142. * to evict even 0-sized elements.
  143. */
  144. public void trimToSize(int maxSize) {
  145. while (true) {
  146. K key;
  147. V value;
  148. synchronized (this) {
  149. if (size < 0 || (map.isEmpty() && size != 0)) { // 状态异常
  150. throw new IllegalStateException(getClass().getName()
  151. + ".sizeOf() is reporting inconsistent results!");
  152. }
  153. if (size <= maxSize || map.isEmpty()) { // 如果当前的size不大于maxSize或者map是空的就break, 不需要进行清除操作.
  154. break;
  155. }
  156. // 上面if中的条件不满足, 需要进行清理工作.
  157. Map.Entry<K, V> toEvict = map.entrySet().iterator().next(); //获取map中最近最少使用的数据,即链表中最开始的节点
  158. key = toEvict.getKey(); // 获取要清除的数据的key
  159. value = toEvict.getValue(); // 获取要清除的数据的value
  160. map.remove(key); // remove操作
  161. size -= safeSizeOf(key, value); // 更新size值
  162. evictionCount++; // evictionCount大小加1.
  163. }
  164. entryRemoved(true, key, value, null); // 发生了remove操作, 调用entryRemoved方法
  165. }
  166. }
  167. /**
  168. * Removes the entry for {@code key} if it exists.
  169. * 根据key从map中将对应的value 删除. 外界可以直接调用该方法进行删除操作.
  170. * @return the previous value mapped by {@code key}.
  171. */
  172. public final V remove(K key) {
  173. if (key == null) { // key不能为null.
  174. throw new NullPointerException("key == null");
  175. }
  176. V previous;
  177. synchronized (this) {
  178. previous = map.remove(key); // 核心操作, 从map中将key对应的值删除.
  179. if (previous != null) {
  180. size -= safeSizeOf(key, previous); // 更新size的值
  181. }
  182. }
  183. if (previous != null) {
  184. entryRemoved(false, key, previous, null); // 发生了remove操作, 调用entryRemoved方法
  185. }
  186. return previous;
  187. }
  188. /**
  189. * Called for entries that have been evicted or removed. This method is
  190. * invoked when a value is evicted to make space, removed by a call to
  191. * {@link #remove}, or replaced by a call to {@link #put}. The default
  192. * implementation does nothing.
  193. *
  194. * <p>The method is called without synchronization: other threads may
  195. * access the cache while this method is executing.
  196. *
  197. * @param evicted true if the entry is being removed to make space, false
  198. * if the removal was caused by a {@link #put} or {@link #remove}.
  199. * @param newValue the new value for {@code key}, if it exists. If non-null,
  200. * this removal was caused by a {@link #put}. Otherwise it was caused by
  201. * an eviction or a {@link #remove}.
  202. */
  203. protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {} // 默认不做任何操作, 根据需要重写.
  204. /**
  205. * Called after a cache miss to compute a value for the corresponding key.
  206. * Returns the computed value or null if no value can be computed. The
  207. * default implementation returns null.
  208. *
  209. * <p>The method is called without synchronization: other threads may
  210. * access the cache while this method is executing.
  211. *
  212. * <p>If a value for {@code key} exists in the cache when this method
  213. * returns, the created value will be released with {@link #entryRemoved}
  214. * and discarded. This can occur when multiple threads request the same key
  215. * at the same time (causing multiple values to be created), or when one
  216. * thread calls {@link #put} while another is creating a value for the same
  217. * key.
  218. * 用来根据key创造一个value, 在get方法中用于返回一个默认值:Null, 可以重写.
  219. */
  220. protected V create(K key) {
  221. return null;
  222. }
  223. private int safeSizeOf(K key, V value) { // 调用sizeOf方法获取value的大小并返回value的大小.
  224. int result = sizeOf(key, value);
  225. if (result < 0) {
  226. throw new IllegalStateException("Negative size: " + key + "=" + value); // 就多了一个
  227. }
  228. return result;
  229. }
  230. /**
  231. * Returns the size of the entry for {@code key} and {@code value} in
  232. * user-defined units. The default implementation returns 1 so that size
  233. * is the number of entries and max size is the maximum number of entries.
  234. * 获取value的大小, 该方法必须重写, 默认返回1.
  235. * <p>An entry's size must not change while it is in the cache.
  236. */
  237. protected int sizeOf(K key, V value) {
  238. return 1;
  239. }
  240. /**
  241. * Clear the cache, calling {@link #entryRemoved} on each removed entry.
  242. * 清除所有的数据.
  243. */
  244. public final void evictAll() {
  245. trimToSize(-1); // -1 will evict 0-sized elements
  246. }
  247. /**
  248. * For caches that do not override {@link #sizeOf}, this returns the number
  249. * of entries in the cache. For all other caches, this returns the sum of
  250. * the sizes of the entries in this cache.
  251. */
  252. public synchronized final int size() {
  253. return size;
  254. }
  255. /**
  256. * For caches that do not override {@link #sizeOf}, this returns the maximum
  257. * number of entries in the cache. For all other caches, this returns the
  258. * maximum sum of the sizes of the entries in this cache.
  259. */
  260. public synchronized final int maxSize() {
  261. return maxSize;
  262. }
  263. /**
  264. * Returns the number of times {@link #get} returned a value that was
  265. * already present in the cache.
  266. */
  267. public synchronized final int hitCount() {
  268. return hitCount;
  269. }
  270. /**
  271. * Returns the number of times {@link #get} returned null or required a new
  272. * value to be created.
  273. */
  274. public synchronized final int missCount() {
  275. return missCount;
  276. }
  277. /**
  278. * Returns the number of times {@link #create(Object)} returned a value.
  279. */
  280. public synchronized final int createCount() {
  281. return createCount;
  282. }
  283. /**
  284. * Returns the number of times {@link #put} was called.
  285. */
  286. public synchronized final int putCount() {
  287. return putCount;
  288. }
  289. /**
  290. * Returns the number of values that have been evicted.
  291. */
  292. public synchronized final int evictionCount() {
  293. return evictionCount;
  294. }
  295. /**
  296. * Returns a copy of the current contents of the cache, ordered from least
  297. * recently accessed to most recently accessed.
  298. */
  299. public synchronized final Map<K, V> snapshot() { // 返回了一个数据的副本.
  300. return new LinkedHashMap<K, V>(map); // 创建了一个新的LinkedHashMap对象并将map中的值复制给它然后返回, 这样外界对返回的对象进行操作不会影响cache中的数据.
  301. }
  302. @Override public synchronized final String toString() {
  303. int accesses = hitCount + missCount;
  304. int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
  305. return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
  306. maxSize, hitCount, missCount, hitPercent);
  307. }
  308. }


参考博客: http://blog.csdn.net/chdjj/article/details/38701509?utm_source=tuicool&utm_medium=referral
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值