如何实现最近使用的缓存

时间:2009-02-24 22:13:25

标签: java algorithm caching java-me mru

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

以下是要求和限制......

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

4 个答案:

答案 0 :(得分:22)

Java Collections提供开箱即用的LinkedHashMap,非常适合构建缓存。你可能在Java ME中没有这个,但你可以在这里获取源代码:

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

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

文档包含通过覆盖removeEldestEntry(Map.Entry)方法构建MRU Cache的说明。你真正需要做的就是创建一个扩展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 传递给广告订单。

答案 1 :(得分:7)

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

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

答案 2 :(得分:2)

为什么要实施已实施的内容?使用Ehcache

然而,如果第三方库完全不可能,我想您正在寻找实现如下所示的数据结构:

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

答案 3 :(得分:0)

另一种方法可能是看看Brian Goetz撰写的 Java Concurrency in Practice 中的5.6节:“构建一个高效,可扩展的结果缓存”。请看一下Memoizer,尽管您可能需要根据自己的需要对其进行自定义。

顺便说一下,我无法弄清楚为什么Java没有开箱即用的ConcurrentLinkedHashMap。这种数据结构对于构建缓存非常有用。