我正在使用WeaekHashMap实现缓存。我想知道是否要遍历此映射的键,并且同时垃圾回收器正在从该映射中主动删除键,我会收到ConcurrentModificationException吗?
我不这么认为,因为据我所知,并发修改异常是由于应用程序代码中的错误而发生的,开发人员忘记了理解相同的映射是由其他线程共享/使用的,在这种情况下,应该不会发生。但是想知道当WeakHashMap不同步时JVM将如何处理吗?

最佳答案

正如bkail所说,当GC从WeakHashMap中“删除”一个条目时,它不会引起并发修改。实际上,GC通过对WeakReference对象(具有实键)本身进行硬引用来收集基础对象。因此,不会收集由映射直接引用的真实对象(引用对象),因此直到您的线程中的一个调用此映射中的方法之前,映射不会更改。那时,映射从GC中检查引用队列,并找到所有已收集的键并将其从映射中删除-因此,对映射结构的实际更改发生在您的线程之一上。

考虑到这一点,那么在某些情况下,您可能会在这样的映射中进行并发修改,而您不会在另一种映射中得到并发修改-如果您放置已经存在的键或调用getter方法。但是,实际上,在并发应用程序中,无论如何,您都应该锁定这些调用,以便在程序中存在真正的并发访问错误。

话虽如此,您实际上不应将 WeakHashMap用于缓存(即使您正在谈论缓存键)。在缓存中,当不再引用值时,您不希望您的值“神奇地”消失。通常,您希望它们在有一定的最大数目时(例如Apache集合 LRUMap )消失,或者根据内存需求释放它们。

对于以后的版本,您可以将 map 与SoftReference一起使用(Apache集合提供了 ReferenceMap ,它允许您指定键或值的引用类型)。指定软引用只能根据内存压力来释放-另一方面,弱引用必须与GC一起做更多事情,因为它认识到对象没有剩余的硬引用,可以随时释放它。当然,软引用的实际工作方式还取决于JVM的实现。

编辑:我重读了您的问题,并想解决另一点。因为实际修改发生在您自己线程上的WeakHashMap内部结构上,所以如果您仅在单个线程中使用此映射,则不需要同步任何方法调用。此行为与其他Map相同。

10-07 23:23