LRU least recently used.顧名思義,是根據數據的活躍度進行更新的緩存算法。
LRU Cache的LinkedHashMap實現:
LinkedHashMap自身已經實現了順序存儲,默認情況下是按照元素的添加順序存儲,也可以啟用按照訪問順序存儲,即最近讀取的數據放在最前面,最早讀取的數據放在最后面,然后它還有一個判斷是否刪除最老數據的方法,默認是返回false,即不刪除數據,我們使用LinkedHashMap實現LRU緩存的方法就是對LinkedHashMap實現簡單的擴展,擴展方式有兩種,一種是inheritance,一種是delegation,具體使用什么方式看個人喜好
//LinkedHashMap的一個構造函數,當參數accessOrder為true時,即會按照訪問順序排序,最近訪問的放在最前,最早訪問的放在后面
public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
//LinkedHashMap自帶的判斷是否刪除最老的元素方法,默認返回false,即不刪除老數據
//我們要做的就是重寫這個方法,當滿足一定條件時刪除老數據
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
采用inheritance方式實現比較簡單,而且實現了Map接口,在多線程環境使用時可以使用 Collections.synchronizedMap()方法實現線程安全操作
package cn.lzrabbit.structure.lru;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Created by liuzhao on 14-5-15.
*/
public class LRUCache2<K, V> extends LinkedHashMap<K, V> {
private final int MAX_CACHE_SIZE;
public LRUCache2(int cacheSize) {
super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
MAX_CACHE_SIZE = cacheSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_CACHE_SIZE;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Map.Entry<K, V> entry : entrySet()) {
sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));
}
return sb.toString();
}
}
這樣算是比較標准的實現吧,實際使用中這樣寫還是有些繁瑣,更實用的方法時像下面這樣寫,省去了單獨見一個類的麻煩
final int cacheSize = 100;
Map<String, String> map = new LinkedHashMap<String, String>((int) Math.ceil(cacheSize / 0.75f) + 1, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
return size() > cacheSize;
}
};
LRU緩存LinkedHashMap(delegation)實現
delegation方式實現更加優雅一些,但是由於沒有實現Map接口,所以線程同步就需要自己搞定了
package cn.lzrabbit.structure.lru;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
/**
* Created by liuzhao on 14-5-13.
*/
public class LRUCache3<K, V> {
private final int MAX_CACHE_SIZE;
private final float DEFAULT_LOAD_FACTOR = 0.75f;
LinkedHashMap<K, V> map;
public LRUCache3(int cacheSize) {
MAX_CACHE_SIZE = cacheSize;
//根據cacheSize和加載因子計算hashmap的capactiy,+1確保當達到cacheSize上限時不會觸發hashmap的擴容,
int capacity = (int) Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTOR) + 1;
map = new LinkedHashMap(capacity, DEFAULT_LOAD_FACTOR, true) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_CACHE_SIZE;
}
};
}
public synchronized void put(K key, V value) {
map.put(key, value);
}
public synchronized V get(K key) {
return map.get(key);
}
public synchronized void remove(K key) {
map.remove(key);
}
public synchronized Set<Map.Entry<K, V>> getAll() {
return map.entrySet();
}
public synchronized int size() {
return map.size();
}
public synchronized void clear() {
map.clear();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Map.Entry entry : map.entrySet()) {
sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));
}
return sb.toString();
}
}
注:此實現為非線程安全,若在多線程環境下使用需要在相關方法上添加synchronized以實現線程安全操作
