Java中LruCache的工作原理

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方法,可以根据具体需求调整缓存策略,从而优化应用的性能和资源使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值