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 及更高版本,则此用例通过ClassValue
https://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 等价物?的主要内容,如果未能解决你的问题,请参考以下文章