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

时间:2012-02-29 23:11:37

标签: 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>();
    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();
    }
}

我正在尝试实现滚动缓存,以便在达到最大缓存大小(常见的发生)时,从缓存中删除最旧的位图。运行我的应用程序会提供以下输出:

02-29 23:00:26.590: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 30
02-29 23:00:26.600: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 30
02-29 23:00:26.720: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 30
02-29 23:00:26.790: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 30
02-29 23:00:26.820: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 31
02-29 23:00:26.850: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 31
02-29 23:00:27.050: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 32
02-29 23:00:27.070: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 32
02-29 23:00:27.100: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 33
02-29 23:00:27.130: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 34
02-29 23:00:27.170: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 35
02-29 23:00:27.210: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 35
02-29 23:00:27.330: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 35
02-29 23:00:27.360: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 35

当缓存大小达到30并且在那里停留几次执行时,代码正确地开始记录“达到最大缓存大小”。但随后它奇怪地开始增加到35个。此时它会在那里停留数百个输出。我不能让它增加到35以上。

我的实施有什么问题?鉴于addBitmapToCache方法已同步,我对高速缓存大小超出最大集合的方式感到困惑。

2 个答案:

答案 0 :(得分:2)

有几个问题。

首先,cachedBitmapUrlsOrderList。如果多次请求相同的位图,会发生什么?您在列表中获得了大量重复的URL。因此,当您第一次达到限制时,您将从列表和地图中删除URL。 但是相同的网址仍在列表中,没有匹配的地图条目。因此,随后从列表中删除相同网址的尝试将从地图中删除任何内容,地图将会增长。

您可以通过addBitmapToCache()开头检查是否已缓存网址bitmapCache.containsKey(url),从而避免这种情况。如果是这样,您不需要修改地图;只需确保将此条目记住为最新条目。

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

此外,get()size()方法也应同步。

并且get()应该更新检索到的条目的时间戳,以便它成为最新的。

答案 1 :(得分:2)

除了格雷厄姆的答案,如果拨打clearCachecachedBitmapUrlsOrder的电话也不会被清除。因此,当您下次达到限制时,您将不会删除任何内容:

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