【问题标题】:How to implement a most-recently-used cache如何实现最近使用的缓存
【发布时间】:2009-02-24 22:13:25
【问题描述】:

实现最近使用的对象缓存的最佳方法是什么?

这是要求和限制...

  • 对象存储为键/值对象/对象对,所以接口有点像Hashtable get/put
  • 调用“get”会将该对象标记为最近使用的对象。
  • 可以随时从缓存中清除最近最少使用的对象。
  • 查找和清除必须快速(如在 Hashtable 中快速)
  • Objects 的数量可能很大,所以列表查找不够好。
  • 必须使用 JavaME 进行实现,因此使用第三方代码或标准 Java 库中整洁的库类的余地很小。出于这个原因,我更多地寻找算法答案而不是建议现成的解决方案。

【问题讨论】:

    标签: java algorithm caching java-me mru


    【解决方案1】:

    Java 集合提供开箱即用的LinkedHashMap,非常适合构建缓存。您可能在 Java ME 中没有此功能,但您可以在此处获取源代码:

    http://kickjava.com/src/java/util/LinkedHashMap.java.htm

    如果您不能只是复制粘贴它,那么查看它应该可以让您开始实施一个以包含在您的移动应用程序中。基本思想只是通过地图元素包含一个链表。如果您在有人放置或获取时保持更新,您可以有效地跟踪访问顺序和使用顺序。

    文档包含通过覆盖 removeEldestEntry(Map.Entry) 方法构建 MRU 缓存的说明。您真正需要做的就是创建一个扩展 LinkedHashMap 的类并像这样覆盖该方法:

    private static final int MAX_ENTRIES = 100;
    
    protected boolean removeEldestEntry(Map.Entry eldest) {
       return size() > MAX_ENTRIES;
    }
    

    还有一个constructor,可让您指定是否希望类通过插入或使用来按顺序存储内容,因此您的驱逐策略也有一点灵活性:

    public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder)
    

    true 用于使用顺序,将 false 用于插入顺序。

    【讨论】:

    • 得分! (我只是来发布同样的东西。)
    • 这看起来非常适合我一直想要实现的东西 - 谢谢!
    • mru 为假,lru 为真
    • SUN 专有/机密
    • 所描述的解决方案将是 LRU 缓存而不是 MRU。
    【解决方案2】:

    由于锁定要求,ConcurrentLinkedHashMap 很难构造。带有锁的 LinkedHashMap 很简单,但并不总是高效的。并发版本将尝试通过锁拆分或理想情况下进行 CAS 操作来减少锁定量,从而使锁定非常便宜。如果 CAS 操作确实变得昂贵,那么类似的桶拆分可能会有所帮助。由于 LRU 需要对每个访问操作进行写入,并且使用双向链表,因此使用纯 CAS 操作实现这一点非常棘手。我已经尝试过了,但我需要继续完善我的算法。如果你搜索 ConcurrentLinkedHashMap,你会看到我的项目页面...

    如果 Java ME 不支持 CAS 操作(我希望这是真的),那么您可以做的就是基本同步。这对于 LHM 来说可能已经足够好了,因为我只在服务器端看到高线程数的性能问题。所以 +1 上面的答案。

    【讨论】:

    • Ben:为什么 Java Collections API 或 Google Collections 中没有 ConcurrentLinkedHashMap? com.google.common.collect.CustomConcurrentHashMap.Builder 可以帮忙吗?你的项目也很好。编辑您的答案以链接到它。
    • Julien:CCHM 非常新,不够灵活,而且似乎是对他们的 ReferenceMap 的重写,以响应 JBoss 在 Java-7 中的 CRHM。它似乎主要是一个定制的 CHM。我们有一个用例,锁定正在杀死我们,所以我只是玩弄了锁拆分的想法并尝试了 CAS。
    【解决方案3】:

    为什么要实施已经实施的东西?使用Ehcache

    然而,如果第三方库完全不可能,我猜你正在寻求实现一个看起来像这样的数据结构:

    • 基本上是一个 HashMap(如果你愿意,可以扩展 HashMap<Object, Object>
    • Map 中的每个值都指向排序列表中的一个对象,根据哪个对象最常用。
    • 最近使用的对象被添加到列表的头部 - O(1)
    • 清除最近最少使用意味着截断列表的末尾 - O(1)
    • 仍为您提供地图查找,但仍将最近使用的项目放在首位...

    【讨论】:

    • 因为我的最后一点......必须在手机上使用JavaME运行。
    • 该算法的问题在于,虽然可以快速查找hashmap中的值,但仍需要在列表中再次查找并将其移到头部。
    • ...虽然在写的时候,我突然意识到哈希图中的值对象可以是一个可以移动到列表头的列表节点对象,而不是实际的值对象本身。耶:)
    【解决方案4】:

    另一种方法可能是查看 Brian Goetz 的 Java 并发实践 中的第 5.6 节:“构建高效、可扩展的结果缓存”。看看 Memoizer,尽管您可能需要根据自己的目的对其进行自定义。

    顺便说一句,我不明白为什么 Java 没有开箱即用的 ConcurrentLinkedHashMap。这种数据结构对于构建缓存非常有帮助。

    【讨论】:

      猜你喜欢
      • 2012-01-09
      • 1970-01-01
      • 1970-01-01
      • 2011-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-04
      • 1970-01-01
      相关资源
      最近更新 更多