WeakHashMap迭代和垃圾收集

Sha*_*mik 14 java

我正在使用a WeaekHashMap来实现Cache.我想知道我是否正在迭代这张地图的键,同时垃圾收集器正在主动从这张地图上删除键,我会收到ConcurrentModificationException吗?我不这么认为,因为据我所知,并发修改是因为应用程序代码中的错误导致开发人员忘记了解相同的映射是由其他线程共享/使用的,在这种情况下,它不应该发生.但是想知道当WeakHashMap不同步时JVM会如何处理?

Kev*_*ock 14

正如bkail所说,当GC"删除"一个条目时,WeakHashMap它不会导致并发修改.实际上,GC通过对WeakReference对象(包含真实密钥)本身的硬引用来收集底层对象.因此,不会收集由映射直接引用的真实对象(引用对象),因此在您的某个线程调用此映射中的方法之前,映射不会更改.此时,映射将检查GC中的引用队列,并查找已收集的所有键并将其从映射中删除 - 因此对映射结构的实际更改将发生在其中一个线程上.

考虑到这一点,可能有一种情况,你可能会在这样的地图中得到一个并发修改,你不会在另一种地图中得到 - 如果你把一个已经存在的密钥或调用一个getter方法.但实际上,在并发应用程序中,您应该锁定这些调用,这样您的程序中就会出现真正的并发访问错误.

在回答你的问题时,你真的不应该使用 WeakHashMap缓存(即使你在谈论缓存密钥).在缓存中,当不再引用值时,您不希望您的值"神奇地"消失.通常,当有一定的最大数量(类似于Apache集合LRUMap)或在内存需求上释放时,您希望它们消失.

对于后者,您可以使用带有的映射SoftReference(Apache集合提供了一个ReferenceMap允许您指定键或值的引用类型).指定软引用仅基于内存压力释放 - 另一方面弱引用必须通过GC识别出对象没有剩余硬引用并且可以随时释放它.当然,软引用如何真正起作用还取决于JVM实现.

编辑:我重读了你的问题,并希望解决另一个问题.因为实际修改发生WeakHashMap在您自己的线程上的内部结构中,如果您只在单个线程中使用此映射,则不需要同步任何方法调用.这种行为与其他行为没有什么不同Map.


Bre*_*ail 5

不,您不会收到ConcurrentModificationException.当您调用各种操作时,WeakHashMap使用ReferenceQueue.poll.换句话说,每个调用者都默默地负责清除Map中的陈旧条目.但是,这确实意味着从多个线程调用WeakHashMap上的方法是不安全的,否则这些线程似乎是"只读",因为对get()的任何调用都可以破坏另一个线程试图迭代的条目链表.