ConcurrentReferenceHashMap如何工作?

时间:2017-11-14 15:12:15

标签: java spring concurrency hashmap

我们有使用spring-cloud-netflix-core库的情况,其中描述了here。我认为问题在于CachingSpringLoadBalancerFactory使用ConcurrentReferenceHashMap报告here的方式。
还有ConcurrentReferenceHashMap(使用软引用)的文档:

  

引用的使用意味着无法保证放入地图的项目随后可用。垃圾收集器可能随时丢弃引用,因此可能看起来未知线程正在静默删除条目。

现在我的问题是:
1.我的理解是否正确?

// Original code is in CachingSpringLoadBalancerFactory in spring-cloud-netflix-core
// cache is a field of type ConcurrentReferenceHashMap
if (this.cache.containsKey(clientName)) {
  return this.cache.get(clientName); // This can be null, right?
}

2。无论如何都要为它编写一个测试用例。我们设法在内存有限的独立应用程序中重现一次(-Xmx50m)。但是,我们如何编写单元测试来涵盖这种情况?

2 个答案:

答案 0 :(得分:0)

关于你的问题,是的,这是对的。通常,这是WeakHashMap的变体,如文档中所述。

WeakHashMap的JavaDoc说:

" WeakHashMap类的行为部分取决于垃圾收集器的操作,因此几个熟悉的(虽然不是必需的)Map不变量不适用于此类。由于垃圾收集器可能随时丢弃密钥,因此WeakHashMap可能表现为未知线程正在静默删除条目。特别是,即使您在WeakHashMap实例上进行同步并且不调用其任何mutator方法,size方法也可能会随着时间的推移返回较小的值,isEmpty方法返回false然后truecontainsKey方法返回true,然后false返回给定密钥,get方法返回null返回给定键的值,但稍后返回putnull方法返回removefalse方法返回getReference()以获取键以前似乎是在地图中,并且对于密钥集,值集合和条目集的连续检查产生了相继较少数量的元素。"

由于这种行为,很难进行测试。如果要测试某些不变量,可以使用地图的release()方法和相应元素的select case when mod(round(dbms_random.value(1,100)),2) = 0 then dbms_output.put_line('M'); when mod(round(dbms_random.value(1,100)),2) = 1 then dbms_output.put_line('W'); end from dual 方法来模拟清除。

答案 1 :(得分:0)

根据我对文档意图的理解,这应该取决于您的键和值是否在地图之外被强烈引用。您不知道是不是这种情况。

但是,地图实现(直到现在)似乎并未实际使用对单个键/值的软/弱引用,而是管理内部的非强引用地图条目,然后根据引用类型将其设为空忽略gc(弱引用)或低内存(软引用),而不考虑键/值的强可达性。修复之前的解决方法(或我的错误报告无效;-))包括使用具有相同名称的Hibernate / Hibernate验证器类(Doug Lee的公共领域实现,而该实现从未以某种方式包含在JDK中)或Guava的MapMaker.weakKeys( ).weakValues(),以防您真的不需要软引用。

请参见https://github.com/spring-projects/spring-framework/issues/24253