LruCache(Least Recently Used Cache)是一种基于最近最少使用原则的缓存机制。它的核心思想是当缓存容量达到上限时,自动淘汰最近最少使用的数据,为新的数据腾出空间。
工作原理
LruCache的实现主要依赖于LinkedHashMap的accessOrder属性。当accessOrder为true时,LinkedHashMap会按照访问顺序维护元素的顺序,这正是实现LRU缓存的关键。
- 数据结构:LruCache内部使用LinkedHashMap来存储键值对,并通过双向链表维护数据的使用顺序。最近使用的数据位于链表头部,最近最少使用的数据位于链表尾部。
- 访问操作:当访问缓存中的数据时,LruCache会将访问的数据移动到链表头部,表示最近使用过。如果数据不在缓存中,则从底层数据源获取数据,并将其插入到链表头部和哈希表中。
- 淘汰机制:当缓存容量达到上限时,LruCache会移除链表尾部的数据项,即最近最少使用的数据。
核心代码解析
以下是LruCache的核心代码实现:
public class LruCache<K, V> {
private final LinkedHashMap<K, V> map;
private int size;
private final int 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);
}
public final V get(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
synchronized (this) {
V value = map.get(key);
if (value != null) {
return value;
}
}
return 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) {
size += safeSizeOf(key, value);
previous = map.put(key, value);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
trimToSize(maxSize);
}
return previous;
}
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.entrySet().iterator().next();
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
}
}
}
private int safeSizeOf(K key, V value) {
int result = sizeOf(key, value);
if (result < 0) {
throw new IllegalStateException("Negative size: " + key + "=" + value);
}
return result;
}
protected int sizeOf(K key, V value) {
return 1;
}
}
如何自定义缓存策略
在实际应用中,可以通过继承LruCache类并重写sizeOf方法来自定义缓存策略。
示例:图片缓存
以下是一个使用LruCache缓存图片的示例:
public class ImageCache {
private static final int MAX_MEMORY = (int) (Runtime.getRuntime().maxMemory() / 1024);
private static final int CACHE_SIZE = MAX_MEMORY / 4;
private LruCache<String, Bitmap> memoryCache;
public ImageCache() {
memoryCache = new LruCache<String, Bitmap>(CACHE_SIZE) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount() / 1024;
}
};
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
memoryCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return memoryCache.get(key);
}
}
在这个示例中,sizeOf方法用于计算每个图片的大小,确保缓存的总大小不超过设定的阈值。
示例:网络请求缓存
以下是一个使用LruCache缓存网络请求结果的示例:
public class NetworkCache {
private static final int MAX_CACHE_SIZE = 1024 * 1024; // 1MB
private LruCache<String, String> responseCache;
public NetworkCache() {
responseCache = new LruCache<String, String>(MAX_CACHE_SIZE) {
@Override
protected int sizeOf(String key, String value) {
return value.getBytes().length;
}
};
}
public void putResponse(String url, String response) {
responseCache.put(url, response);
}
public String getResponse(String url) {
return responseCache.get(url);
}
}
在这个示例中,sizeOf方法用于计算每个响应的大小,确保缓存的总大小不超过设定的阈值。
通过自定义sizeOf方法,可以根据具体需求调整缓存策略,从而优化应用的性能和资源使用。
858

被折叠的 条评论
为什么被折叠?



