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

Seb*_*ber 8 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() );
}
Run Code Online (Sandbox Code Playgroud)

此代码生成输出:

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
Run Code Online (Sandbox Code Playgroud)

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

Kev*_*ion 13

softKeys从来没有意义,所以我们删除了方法.softValues假设值实例在缓存之外的其他方式也不可达,这是软refs有意义的唯一方法.

然后使用weakKeys基本归结为你是否想要密钥的身份相同.如果密钥覆盖equals,你需要的是平等的行为,你不能使用它.如果你想要身份,那么weakKeys你是如何得到它的,这也是有道理的,因为一旦所有其他对密钥的引用都已经GC了,无论如何都无法查找该条目,所以它也可能被删除.

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

  • @KevinBourrillion,请检查我的编辑.正如我所说,一个密钥可以序列化,反序列化例如.我认为如果Guava重写SoftReference的equals方法,软键会有意义.我已经看到Guava使用了"等价机制",我认为,对于软引用,defaultEquivalence不应该是identity而是equals,以处理这种情况.然后,使用softKeys会有意义,因为您可以通过密钥副本检索映射值.你怎么看? (3认同)
  • 因此,如果您使用弱键并且在缓存之外不再有键引用,键会被收集,但是值会发生什么?它们是否保存在缓存中? (2认同)