天天看點

LruCache使用解讀

LruCache使用解讀
之前在網上有看到一篇文章《2017下半年,一二線網際網路公司Android面試題彙總》,整理的知識點還挺全而且也有一些比較深入的點,最初看的時候有些知識點要麼答不上來,要麼了解的不夠深刻,後面也是查閱了很多相關資料才弄明白。正所謂“好記性不如爛筆頭”,為了加深自己的了解以及友善以後查閱,是以打算寫一些文章記錄下來,于是就有了第一個知識點LruCache。這裡我們将通過3W(What,Why和How)的方式來說明LruCache。

什麼是LruCache?

LruCache是Android在API12上引入的一種緩存機制,這種緩存有個特點,就是當緩存容量達到上限時,會将最近最少使用的對象從cache中清除出去。

那麼這種緩存方式跟普通的緩存有什麼差別呢?為什我需要使用它?

曾經,在各大緩存圖檔的架構沒流行的時候。有一種很常用的記憶體緩存技術:SoftReference 和 WeakReference(軟引用和弱引用),但是走到了 Android 2.3(Level 9)時代,垃圾回收機制更傾向于回收 SoftReference 或 WeakReference 的對象。後來,又來到了Android3.0,圖檔緩存在native中,因為不知道要在是什麼時候釋放記憶體,沒有政策,沒用一種可以預見的場合去将其釋放,這就造成了記憶體溢出。

是以LruCache的出現就是為了解決上述問題,它使用強引用來緩存,消除了垃圾回收機制的影響,同時通過設定緩存上限以及著名的LRU算法來管理記憶體,使得記憶體的管理變得更加高效和靈活。

如何使用LruCache?

LruCache是通過LinkedHashMap來實作LRU記憶體管理的,是以我們可以将其當作一個map來使用,如put,get,remove等。但是要注意,LruCache是不允許key和value為空的。

接下來是針對LruCache這個知識點的一些延伸

Lru是什麼?

LRU是作業系統記憶體管理中比較經典的一種緩存淘汰算法,相信學過作業系統的童鞋應該都有耳聞。作業系統裡面還存在一些其他的緩存淘汰算法,如LIFO,FIFO,LFU等,它們都是從某一個次元來評估緩存中條目的重要性,進而當緩存不足時淘汰掉其中最不重要的條目。可見當我們在做App開發時,作業系統裡面很多的技術思想其實也可以拿來做參考。

LinkedHashMap為什麼能實作LruCache中的Lru?

LinkedHashMap跟HashMap一個重要差別就是其内部的entry是有序的,它有兩種排序規則:插入排序和通路排序,其實也就是按put調用時間排序還是按get調用時間來排序。LinkedHashMap通過設定通路排序來是實作Lru的。

LruCache在多線程通路時是否需要加同步鎖?

LruCache内部使用了synchronized來保證其線程安全。是以當我們在通路lrucache時并不需要加鎖,但是在一個線程中如果出現多次讀寫,則需要對cache額外加鎖。比如

synchronized (cache) {
     if (cache.get(key) == null) {
         cache.put(key, value);
     }
}
           

上面講到lrucache中使用了synchronized來同步,那麼在app開發中有哪些比較常見的同步方式呢?

  1. 第一個是synchronized,因為使用起來非常簡單是以排在了第一個,并且在jdk1.6以後其性能得到了極大優化使得其使用更加廣泛。
  2. 第二個是reentrantlock,在jdk1.5之前其相對synchronized具有性能優勢,并且由于這種鎖的靈活性,比如逾時鎖,中斷鎖等,使得其在某些場合下使用更具優勢。
  3. 第三個是AtomicXXX,準确來說這不算是一種鎖,但是由于其操作的原子性,我們經常會在一些場合,比如計數AtomicInteger,标記AtomicBoolean等用到。可能有人會說volatile也可以做到,但是像讀後寫,自增等操作卻是volatile無法做到的,是以對于原始資料的多線程通路,建議優先使用AtomicXXX。

繼續閱讀