Android 为什么我的缓存机制没有按预期工作?

Android 为什么我的缓存机制没有按预期工作?,android,caching,concurrency,Android,Caching,Concurrency,这件事把我难住了。我有一个静态类,它管理下载的位图图像的缓存。该类由多个线程访问,可能并发访问。以下是实现: public class BitmapCache { private static final int MAX_NUMBER_BITMAPS_TO_CACHE = 30; private static Map<String, Bitmap> bitmapCache = new HashMap<String, Bitmap>(); priva

这件事把我难住了。我有一个静态类,它管理下载的位图图像的缓存。该类由多个线程访问,可能并发访问。以下是实现:

public class BitmapCache {
    private static final int MAX_NUMBER_BITMAPS_TO_CACHE = 30;
    private static Map<String, Bitmap> bitmapCache = new HashMap<String, Bitmap>();
    private static List<String> cachedBitmapUrlsOrder = new ArrayList<String>();

    private BitmapCache(){}

    public static synchronized void addBitmapToCache(String url, Bitmap bitmap) {
        if (bitmapCache.size() >= MAX_NUMBER_BITMAPS_TO_CACHE) {
            Log.i("MyApp", "Max cache size reached.  Removing oldest bitmap.  Size = " + bitmapCache.size());
            String oldestUrl = cachedBitmapUrlsOrder.remove(0);
            bitmapCache.remove(oldestUrl);
        }
        bitmapCache.put(url, bitmap);
        cachedBitmapUrlsOrder.add(url);
    }

    public static int size() {
        return bitmapCache.size();
    }

    public static Bitmap get(String url) {
        return bitmapCache.get(url);
    }

    public synchronized static void clearCache() {
        bitmapCache.clear();
    }
}
当缓存大小达到30时,代码正确地开始记录“已达到最大缓存大小”,并在那里停留几次执行。但奇怪的是,它开始增加到35。在这一点上,它停留在那里的数百多个输出。我不能让它超过35

我的实现有什么问题?由于
addBitmapToCache
方法是同步的,我对缓存大小如何超过最大设置感到困惑。

有几个问题

首先,
cachedBitmapUrlsOrder
是一个
列表
。如果多次请求同一位图,会发生什么情况?列表中有一大堆重复的URL。因此,当您第一次达到限制时,您将从列表和地图中删除URL但相同的URL仍在列表中,没有匹配的地图条目。因此,后续从列表中删除相同URL的尝试不会从映射中删除任何内容,映射将增长

如果URL已经被缓存,可以通过在
addBitmapToCache()
的开始处使用
bitmapCache.containsKey(URL)
进行检查来避免这种情况。如果是这样,您不需要修改地图;只需确保此条目被记住为最新条目

或者,将列表更改为唯一值的集合;可能是URL到时间戳的映射,或一组。(我让你决定。)

此外,还应该同步
get()
size()
方法


get()
应该更新检索到的条目的时间戳,使其成为最新的。

此外,如果调用
clearCache
cachedBitmapUrlsOrder
未被清除,Graham的回答也是如此。因此,当您下次达到某个限制时,您不会在此处删除任何内容:

String oldestUrl = cachedBitmapUrlsOrder.remove(0);
bitmapCache.remove(oldestUrl); // bitmapCache does not have such key

在Jave中,当您执行.remove(0)时,它会自动为您向下移动其余的项目吗?根据javadoc,它会……在从地图中删除后,也许值得再次记录该项目的大小,以确保确实删除了某个项目?@assylias,很好。当缓存每增加一步超过30时,
bitmapCache.remove(oldestUrl)
都无法从缓存中删除该项。你知道怎么会这样吗?我想格雷厄姆对复制品有很好的看法。看起来不存在Concurrency问题。就其增长的原因达成一致,但在检查map.containsKey(url)?@cotton.m是的,在我的答案中添加了这一行,这不是最简单的方法吗。谢谢。又是一个很棒的收获。很明显,我又回到了开发者101。
String oldestUrl = cachedBitmapUrlsOrder.remove(0);
bitmapCache.remove(oldestUrl); // bitmapCache does not have such key