WeakHashMap 是不是有 java.util.concurrent 等价物?

Posted

技术标签:

【中文标题】WeakHashMap 是不是有 java.util.concurrent 等价物?【英文标题】:Is there java.util.concurrent equivalent for WeakHashMap?WeakHashMap 是否有 java.util.concurrent 等价物? 【发布时间】:2011-01-16 09:22:33 【问题描述】:

是否可以不使用Collections.synchronizedMap() 重写以下代码,同时保持并发的正确性?

Collections.synchronizedMap(new WeakHashMap<Class, Object>());

即java.util.concurrent 有什么可以代替的吗?请注意,仅替换为

new ConcurrentHashMap<Class, Object>(new WeakHashMap<Class, Object>()));

显然不行

【问题讨论】:

ConcurrentHashMap 等高并发数据结构的重要好处是它可以(通过各种技术)在重负载下保持线程安全,而不会(大量)阻塞。重要的是要意识到,如果您的类没有承受重负载,那么使用 ConcurrentHashMap 的性能可能会更差而不是使用 HashMap。如果您的环境预计在很大程度上没有争用,您可以使用外部同步,那么您就可以了。 【参考方案1】:

Guava 的CacheBuilder 类可以让您轻松做到这一点。

CacheBuilder.newBuilder().weakKeys().build()

请注意,这会将关键相等语义更改为 == 而不是 .equals(),这在您使用 Class 实例的情况下无关紧要,但这是一个潜在的陷阱。

【讨论】:

Guava 的更新链接:github.com/google/guava 和 CacheBuilder 的更新链接:google.github.io/guava/releases/18.0/api/docs/com/google/common/…【参考方案2】:

我不相信有。事实上,javadoc 建议使用 Collections.synchronizedMap()

“像大多数集合类一样,这个类是不同步的。可以使用 Collections.synchronizedMap 方法构造一个同步的 WeakHashMap。”

【讨论】:

@rogerdpack:但您始终可以将 WeakHashMap 组合成一个滚动您自己的ThreadSafeWeakHashMap,并使用监视器锁,非常容易地编写您自己的 putIfAbsent(...)。同意这在重负载下不是最理想的,但并不是所有的东西都是重负载的。 @rogerdpack 现在可以了,Java 8 ftw【参考方案3】:

Cafeine 是 Guava 缓存的热门竞争对手。

- keys automatically wrapped in weak references
- values automatically wrapped in weak or soft references

用法:

LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
 .weakKeys()
 .weakValues()
 .build(key -> createExpensiveGraph(key));

【讨论】:

【参考方案4】:

在同步映射中包装 WeakHashMap 是否仍然有效 正确地做你想做的事,因为垃圾收集器可以 随时直接修改弱引用,绕过 同步地图包装?我认为 WeakHashMap 只在一个 单线程模型。

如上所述,https://docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html 的 WeakHashMap 文档特别指出:

"一个同步的 WeakHashMap 可以使用 Collections.synchronizedMap 方法”

这对我来说意味着这种技术必须与垃圾收集器的行为协同工作(除非文档有问题!)

【讨论】:

正确。 JVM 始终是多线程的。有 GC 线程、终结器线程等。如果 WeakHashMap 不能在显式多线程 Java 程序中工作,那么也很难看出它如何在单线程程序中工作。 嗯?你错过了整个问题。他要求的是 ConcurrentHashMap 的弱版本(它使用与 WeakHashMap 不同的算法)。【参考方案5】:

如果您使用的是 Java 7 及更高版本,则此用例通过ClassValuehttps://docs.oracle.com/javase/7/docs/api/java/lang/ClassValue.html 以线程安全的方式解决如果您需要使用remove,请仔细考虑并发性并通读文档。

如果您使用的是 Java 6 或更低版本。不,您必须同步 WeakHashMap。

【讨论】:

【参考方案6】:

如果您的类路径中已经有 Spring 框架,那么一种选择是ConcurrentReferenceHashMap

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/ConcurrentReferenceHashMap.html

您可以选择使用weak 或soft 引用(对于键和值)。

【讨论】:

【参考方案7】:

由于垃圾收集器可以随时直接修改弱引用,绕过同步映射包装器,将 WeakHashMap 包装在同步映射中是否仍然可以正常工作?我认为 WeakHashMap 只能在单线程模型中真正起作用。

【讨论】:

以上是关于WeakHashMap 是不是有 java.util.concurrent 等价物?的主要内容,如果未能解决你的问题,请参考以下文章

JDK源码分析之 WeakHashMap 相关

Java的弱引用—WeakHashMap

WeakHashMap垃圾回收原理

什么是WeakHashMap--转

浅谈 WeakHashMap

容器--WeakHashMap