Java中是否有SoftHashMap?

我知道在java.util中有一个WeakHashMap,但是因为它使用WeakReferences来处理所有的事情,只有这个Map被引用,所以在下一个GC循环中被引用的对象将会丢失。 所以如果你想要caching随机数据,这几乎是没有用的,而这些数据很可能在没有被其他时间硬连接的情况下再次被请求。 最好的解决scheme是使用SoftReferences的地图,但是我没有在Java RT Package中find它。

编辑(2012年8月):

事实certificate,目前最好的解决scheme可能是Guava 13.0的Cache类,在Guava的Wiki上解释 – 这就是我将要使用的。 它甚至支持构build一个SoftHashMap (请参阅CacheBuilder.newBuilder().softKeys() ),但它可能不是你想要的,正如Java专家Jeremy Manson所解释的(下面你会发现这个链接)。


不是我所知道的 (2008年11月),但你在网上find一些SoftHashMap的实现。

像这样: SoftHashMap或这个 。


编辑(2009年11月)
正如Matthias在评论中提到的那样, Google Guava MapMaker确实使用了SoftReferences:

一个ConcurrentMap构build器,提供这些function的任意组合:

  • 软键或弱键,
  • 软或弱值,
  • 定时到期,和
  • 按需计算值。

正如在这个线程中提到的,另一个JSR166y候选人:

jsr166y.ConcurrentReferenceHashMap

它为Google实现提供了一个可选的并发参考映射(它依赖后台线程来驱逐条目)


编辑(2012年8月)

Google实现只有在请求条目超时时才使用后台线程。 特别的,它只是简单的使用java.util.Timer ,它不像拥有一个单独的后台线程那么具有侵入性。

Jeremy Mansonbuild议,对于任何caching,使用此function来避免SoftReference的危险: http : //jeremymanson.blogspot.de/2009/07/how-hotspot-decides-to-clear_07.html

Apache Commons还有另一个实现,即org.apache.commons.collections.map.ReferenceMap ; 它不支持定时移除,但它支持select是否通过身份或平等比较密钥。 而且,这个实现不是并发的 – 可以同步,但是在multithreading访问下工作不太好。

我熟悉两个提供SoftHashMap实现的库:

  1. Apache Commons :org.apache.commons.collections.map.ReferenceMap

  2. Google Collections :com.google.common.collect.ReferenceMap

在java专家简报98期中有一个示例实现

Apache Shiro带有一个专为caching而devise的SoftHashMap。 它基于上面jb发布的文章,并在Apache v2下许可。 你可以在这里find文档和源代码。

你有没有考虑使用LRUMap而不是软HashMap? 你可以更好地控制存储的内容(或者至less有多less)。

如果你想实现一个caching,softreference比weak引用更好,但它会把你的整个caching清除策略交给垃圾收集器。 这可能不是你想要的。

如果caching删除政策是重要的,你将需要自己做,最有可能使用常规的引用。 但是,你将不得不决定何时popup物品和popup哪些物品。 如果您只想在堆空间不足时丢失内容,则可以通过以下方式查询可用的堆空间:

 Runtime.getRuntime().getFreeMemory(); 

然后,一旦空闲内存降到一定数量以下,就可以开始丢弃物品。 或者你可以实现caching的最大大小,并使用它来决定何时放弃的东西。

这里是一个LRUcaching,我devise了O(1)插入,删除和查找时间,它有一个可configuration的最大数量的元素。 如果你想要一个caching,这将是一个比SoftHashMap更好的解决scheme。

softreferences是创build可增长caching的好方法。 所以理想的解决scheme是使用SoftHashMap和常规的固定大小caching。 将所有插入caching的内容放入固定caching和软散列映射中,然后引用某些东西,看它是否在软散列表中(并更新caching中的引用时间)。 通过这种方式,所有最重要的项目(根据您select的策略LRU,MFU,…)将永远不会被删除,因为它们在caching中很难被引用,但是您也将持续更多的事情(不受策略控制)因为有足够的记忆。