java - 使用弱/软的 Guava CacheBuilder 或 MapMaker

标签 java caching guava

我不习惯处理 Java 中的软引用和弱引用,但我理解其中的原理,因为我习惯处理像 Gemfire 这样的数据网格,它在内存已满时提供溢出到硬盘功能,可能使用软引用或我猜是类似的东西。

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

例如,我只是想知道使用非软值创建软键有什么意义? 我的意思是,当开始收集软引用时,我们无法再通过其键找到条目,那么为什么我们希望值保留在映射中?

谁能给我们一些用例:

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

谢谢


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

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

编辑: 正如 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 仍然存在于映射中。 但请注意,我仍然无法使用新创建的 key “new KeyHolder("tata");”找到我的条目 这是因为,我的键有意义地等于,但它们周围的引用包装器不等于,因为它们的 equals 方法在 Guava 中没有被覆盖! 在这种情况下,是的,softKeys 没有任何意义,因为您绝对需要保留对该 key 的身份引用才能检索它。

最佳答案

softKeys 从来没有意义,所以我们删除了该方法。 softValues 是软引用唯一有意义的方式,假设值实例也无法通过缓存外的其他方式访问。

weakKeys 的使用基本上归结为您是否希望键的身份相等。如果键覆盖 equals 并且您需要 that 相等行为,则不能使用它。如果你想要身份,那么 weakKeys 就是你得到它的方式,它也很有意义,因为一旦对 key 的所有其他引用都被 GC,无论如何都无法查找该条目, 因此不妨将其删除。

我实际上并不完全清楚 weakValues 何时有用,并且打算研究它。这可能是这样一种情况,其中 weakKeys 不是一个选项(例如,Integer 键),并且通常通过其他方式(例如某种 session )强烈引用值对象,但是当那个对象消失时,它意味着没有人会再在缓存中寻找它。不过,我这样说似乎有点牵强。

关于java - 使用弱/软的 Guava CacheBuilder 或 MapMaker,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10977315/

相关文章:

java - InetAddresses 的 isInetAddress 和 isUriInetAddress 的区别

java - 继承的方法是否计入 Android 中的 Dex 方法限制?

Java 处理大量具体工厂

ruby-on-rails - 检查 Rails.cache 对象的 ttl

guava - 使用标准库组合两个可迭代对象 -- 或 -- 映射与多个可迭代对象

java - 如何使用 Guava 初始化空的 ImmutableEnumMap?

java: (String[])List.toArray() 给出 ClassCastException

Java-使用HashMap实现矩阵

java - 缓存驱逐在没有 key 的情况下不起作用,并且方法没有参数?

ios - 快速缓存.. iOS FBApi