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

时间:2012-06-11 09:18:38

标签: java caching guava

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

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

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

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

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

由于


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

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

修改 正如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().<KeyHolder,String>makeMap() );


    System.out.println("\n\n");
    System.out.println("TESTING SOFT KEYS");
    testMap(new MapMaker().softKeys().<KeyHolder, String>makeMap());


    System.out.println("\n\n");
    System.out.println("TESTING SOFT REFERENCES");
    KeyHolder key1 = new KeyHolder("toto");
    KeyHolder key2 = new KeyHolder("toto");
    SoftReference<KeyHolder> softRef1 = new SoftReference<KeyHolder>(key1);
    SoftReference<KeyHolder> softRef2 = new SoftReference<KeyHolder>(key2);
    System.out.println( "equals keys? " + key1.equals(key2) );
    System.out.println( "equals ref? " + softRef1.equals(softRef2) );
}

private static void testMap(Map<KeyHolder,String> 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");”找到我的条目 这是因为,我的键有意义地等于,但是它们周围的引用包装器不等于因为它们的等号方法没有在Guava中被覆盖! 在这种情况下,是的,softKeys并不意味着什么,因为你绝对需要保持对该密钥的身份引用才能检索它。

2 个答案:

答案 0 :(得分:13)

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

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

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

答案 1 :(得分:2)

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

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

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