是否有java.util.concurrent中WeakHashMap的等效替代品?

59

以下代码片段是否可以被重写,而不使用Collections.synchronizedMap()方法,同时在并发时保持正确性?

Collections.synchronizedMap(new WeakHashMap<Class, Object>());
即,是否有java.util.concurrent中的某些东西可以使用?请注意,仅仅用 </p>进行替换是不够的。
new ConcurrentHashMap<Class, Object>(new WeakHashMap<Class, Object>()));

显然不会起作用


2
高度并发数据结构(例如ConcurrentHashMap)的重要好处是,它可以通过各种技术在重负载下保持线程安全,而不会(太多)阻塞。需要注意的是,如果您的类没有承受重负载,那么使用ConcurrentHashMap的性能可能比使用HashMap还要差。如果您的环境预计很少有争用,那么您可以使用外部同步,这样就可以正常运行。 - scottb
7个回答

43

GuavaCacheBuilder 类可以轻松实现此操作。

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

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


1
更新 Guava 的链接:https://github.com/google/guava 以及 CacheBuilder 的更新链接:https://google.github.io/guava/releases/18.0/api/docs/com/google/common/cache/CacheBuilder.html - Brad Cupit

23

我不认为有。实际上,Javadoc建议使用Collections.synchronizedMap()。

"像大多数集合类一样,该类未同步。可以使用Collections.synchronizedMap方法构造同步的WeakHashMap。"


@rogerdpack:但你总是可以将WeakHashMap组合成一个自己的“ThreadSafeWeakHashMap”,并使用监视器锁定轻松编写自己的putIfAbsent(...)。同意,在重负载下这可能不是最佳选择,但并非所有情况都会有重负载。 - scottb
1
@rogerdpack,现在可以了,Java 8 赢了。 - qualidafial

2

Caffeine 是 Guava cache 的一个受欢迎的竞争对手。

- 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));

1
包装WeakHashMap在同步映射中是否仍然能够按照您所需的方式正常工作,因为垃圾收集器可以随时直接修改弱引用,绕过同步映射包装器?我认为WeakHashMap只在单线程模型中真正起作用。
如上所述,WeakHashMap的文档https://docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html明确说明:
“可以使用Collections.synchronizedMap方法构造同步的WeakHashMap”
这意味着这种技术必须与垃圾收集器的行为配合使用(除非文档存在错误!)。

正确。JVM 总是多线程的。有 GC 线程,终结器线程和其他线程。如果 WeakHashMap 在明确设计为多线程的 Java 程序中无法工作,那么很难看出它如何能在单线程程序中工作。 - Doradus
什么?你没有理解整个问题。他正在寻求ConcurrentHashMap的弱版本(它使用与WeakHashMap不同的算法)。 - Stefan Reich

1

-1

如果将WeakHashMap包装在同步映射中,是否仍然可以正确地实现您想要的功能,因为垃圾回收器可以随时直接修改弱引用,绕过同步映射包装器?我认为WeakHashMap只在单线程模型中真正起作用。


-1

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接