具有弱/软使用的Guava CacheBuilder或MapMaker

我不习惯在Java中处理Soft和Weak引用,但我理解这个原理,因为我习惯于处理像Gemfire这样的数据网格,它在内存已满时为hddfunction提供溢出,可能使用软引用或类似的东西我猜测。

在番石榴中我不明白的是它提供了使键变软/弱的方法,以及值软/弱的方法。

我只是想知道用非软值创建软键的重点是什么? 我的意思是,当开始收集软引用时,我们无法通过其键找到条目,那么为什么我们希望这些值保留在地图中?

有人可以给我们一些用例:

  • 弱键/软值
  • 弱键/正​​常值
  • 软键/弱值
  • 软键/正常值

谢谢


编辑我不确定我的问题是否足够精确,所以我想知道的是:

  • 收集密钥(弱/软)时,该值会发生什么变化(非弱/软)
  • 当收集一个值(弱/软)时,密钥会发生什么
  • 具有缺失部分(键或值)的条目是否保留在缓存中?
  • 当您希望此类条目保留在缓存中时,是否有任何用例。

编辑:正如Kevin Bourillon的回答所讨论的,最后我想我明白为什么使用软键并不意味着什么。 原因如下:

static class KeyHolder { final private String key; public KeyHolder(String key) { this.key = key; } public String getKey() { return key; } @Override public boolean equals(Object o) { KeyHolder that = (KeyHolder)o; boolean equality = this.getKey().equals(that.getKey()); return equality; } @Override public int hashCode() { return key != null ? key.hashCode() : 0; } @Override public String toString() { return "KeyHolder{" + "key='" + key + '\'' + '}'; } } public static void main(String[] args) { System.out.println("TESTING WEAK KEYS"); testMap( new MapMaker().weakKeys().makeMap() ); System.out.println("\n\n"); System.out.println("TESTING SOFT KEYS"); testMap(new MapMaker().softKeys().makeMap()); System.out.println("\n\n"); System.out.println("TESTING SOFT REFERENCES"); KeyHolder key1 = new KeyHolder("toto"); KeyHolder key2 = new KeyHolder("toto"); SoftReference softRef1 = new SoftReference(key1); SoftReference softRef2 = new SoftReference(key2); System.out.println( "equals keys? " + key1.equals(key2) ); System.out.println( "equals ref? " + softRef1.equals(softRef2) ); } private static void testMap(Map map) { KeyHolder strongRefKey = new KeyHolder("toto"); KeyHolder noStrongRefKey = new KeyHolder("tata"); map.put(strongRefKey,"strongRef"); map.put(noStrongRefKey,"noStrongRefKey"); // we replace the strong reference by another key instance which is equals // this could happen for exemple in case of serialization/deserialization of the key noStrongRefKey = new KeyHolder("tata"); System.gc(); System.out.println( "strongRefKey = " + map.get(strongRefKey) ); System.out.println( "noStrongRefKey = " + map.get(noStrongRefKey) ); System.out.println( "keyset = " + map.keySet() ); } 

此代码生成输出:

 TESTING WEAK KEYS strongRefKey = strongRef noStrongRefKey = null keyset = [KeyHolder{key='toto'}] TESTING SOFT KEYS strongRefKey = strongRef noStrongRefKey = null keyset = [KeyHolder{key='tata'}, KeyHolder{key='toto'}] TESTING SOFT REFERENCES toto == toto -> true equals keys? true equals ref? false 

如您所见,使用(已弃用的)软键映射,包含“tata”的KeyHolder仍然存在于地图中。 但请注意,我仍然无法使用新创建的密钥“ new KeyHolder("tata");找到我的条目new KeyHolder("tata");这是因为,我的密钥有意义等于,但是它们周围的引用包装不等于因为它们的等于方法在番石榴中没有被覆盖! 在这种情况下,是的,softKeys并不意味着什么,因为你绝对需要保持对该密钥的身份引用才能检索它。

softKeys永远不会有意义,因此我们删除了该方法。 softValues是软refs有意义的唯一方法,假设值实例在缓存之外的其他方式也不可访问。

然后使用weakKeys基本上归结为你是否想要密钥的身份相等。 如果键覆盖equals并且您需要等同行为,则无法使用它。 如果你想要身份,那么weakKeys就是你如何得到它的,而且它也是有意义的,因为一旦所有其他对密钥的引用都已经GC了,无论如何也无法查找该条目,所以它也可能是除去。

我实际上并不完全清楚weakValues有用,并且会调查它。 可能是这样的情况,其中weakKeys不是一个选项(例如, Integer键),并且值通常通过其他方式强烈引用,如某种会话对象,但当对象消失时,它表示没有人将在缓存中寻找这个。 不过,当我这么说时,它似乎有点牵强。

非Guava WeakHashMap基于弱密钥,并在密钥不再使用时丢弃整个条目。 因此,那时没有“留在地图上的价值”。 这是我从这种数据结构中直观地期望的行为,我强烈怀疑Guava的行为方式相同,也适用于收集的软引用。

请注意,Java Collections库仅提供弱键/正常值映射,而不是弱键/软值或弱键/弱值,因为用户可以自己包装值(但不能将键作为查找对于实际键和对键的弱引用,不应期望hashmap的工作方式相同。

我自己曾经使用过一次WeakHashMap来关联那些可能被其他地方的机制过时的对象与那种机制无关的信息(确切地说:移动可能被某些碰撞破坏的球与他们最近的移动信息)。 这些值是专门为该映射创建的,而不是在其他地方引用的(除了本地只能在其键仍然存在时才能调用的方法)。 因此,除了正常引用值之外,不需要使用任何其他任何东西,因为当密钥变得过时时,该值将变为未引用且可垃圾收集。