【问题标题】:Why is my caching mechanism not working as expected?为什么我的缓存机制没有按预期工作?
【发布时间】:2012-03-19 11:19:58
【问题描述】:

我完全被这个难住了。我有一个静态类,它管理下载的位图图像的缓存。此类由具有并发访问潜力的多个线程访问。这是实现:

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 方法是同步的,我对缓存大小如何超过最大设置感到困惑。

【问题讨论】:

  • 在 Jave 中,当您执行 .remove(0) 时,它会自动为您向下移动其余项目吗?
  • 根据 javadoc 它确实...
  • 也许值得在从地图中移除后再次记录大小以确保项目已真正被移除?
  • @assylias,很好。在缓存增加超过 30 的每一点,bitmapCache.remove(oldestUrl) 无法从缓存中删除该项目。有什么想法会发生这种情况吗?
  • 我认为 Graham 关于重复的观点非常好。看起来没有并发问题。

标签: android caching concurrency


【解决方案1】:

几个问题。

首先,cachedBitmapUrlsOrder 是一个List。如果多次请求同一个位图会怎样?您会在列表中获得一大堆重复的 URL。因此,当您第一次达到限制时,您从列表和地图中删除了一个 URL。 但相同的 URL 仍在列表中,没有匹配的地图条目。因此,后续从列表中删除相同 URL 的尝试将不会从地图中删除任何内容,并且地图将会扩大。

您可以通过在 addBitmapToCache() 的开头检查 URL 是否已缓存,使用 bitmapCache.containsKey(url) 来避免这种情况。如果是,则无需修改地图;只需确保此条目被记住为最新条目即可。

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

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

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

【讨论】:

  • 同意它增长的原因,但在添加到缓存方法的开头添加一行检查 map.containsKey(url) 不是最简单的吗?
  • @cotton.m 是的,将其添加到我的答案中。谢谢。
【解决方案2】:

除了格雷厄姆的回答,如果呼叫clearCachecachedBitmapUrlsOrder 不会被清除。因此,当您下次达到限制时,您将不会在此处删除任何内容:

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

【讨论】:

  • 另一个很棒的收获。对我来说,显然它回到了 Developer 101。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-29
  • 2020-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-28
  • 2014-10-18
相关资源
最近更新 更多