我正在阅读关于WeakHashMap的Java,我了解基本概念。因为GC线程在后台运行,所以您可以得到“不寻常的行为”,例如迭代时的ConcurrentModificationException等等。
我不明白的是,如果默认实现没有同步,并且不以任何方式包含锁,那么为什么不可能得到不一致的状态。假设你有两条线。GC线程在某个索引中删除某个键,同时在同一索引处删除某个键,用户线程在数组中插入一个键值对。
对我来说,如果没有同步,那么获得不一致的散列映射的风险就很高。
更糟糕的是,这样做可能会非常危险,因为v实际上可能是空的。
if (map.contains(k)) {
V v = map.get(k)
}我是不是遗漏了什么?
发布于 2018-01-23 21:50:19
您提到的不一致状态问题不会出现,因为GC没有主动地重构WeakHashMaps。当垃圾收集器释放弱引用的引用时,对应的条目不会物理地从映射中删除;条目只是变得陈旧,没有键。稍后,在地图上的其他操作中,条目可能会被实际删除,但GC不会承担此责任。
您可以看到一个Java版本在grepcode上实现了这个设计。
发布于 2018-01-23 21:40:35
您所描述的是文档明确指出的内容:
因为垃圾收集器可以在任何时候丢弃键,所以
WeakHashMap的行为可能就像一个未知的线程正在悄悄地删除条目一样。
您所犯的唯一错误是假设您可以通过同步来保护状态。这不起作用,因为同步在GC方面不会是相互的。引用下列文件:
特别是,即使您在
WeakHashMap实例上同步,并且没有调用它的mutator方法,size方法也有可能随时间返回较小的值,isEmpty方法返回false,然后返回true,containsKey方法返回true,稍后返回给定键的false,get方法返回给定键的值,但稍后返回null,返回put方法返回null,而remove方法返回以前出现在地图上的密钥,并对键集、值集合和条目集进行连续检查,以依次生成较小数量的元素。
发布于 2018-01-23 21:40:53
这个类主要用于关键对象,其相等方法使用==运算符测试对象标识。一旦这样的键被丢弃,它就永远无法被重新创建,因此不可能在以后的某个时候在WeakHashMap中查找该键,并且对它的条目被删除感到惊讶。
因此,如果对基于身份检查的对象使用WeakHashMap,那么一切都很好。您提到的第一种情况(“GC线程删除某个索引中的某个键,同时在同一索引处,用户线程在数组中插入一个键值对”)。这是不可能的,因为只要用户线程保持对键对象的引用,它就不能被GC丢弃。
第二个例子也是这样:
if (map.contains(k)) {
V v = map.get(k)
}您保留引用k,这样就可以访问相应的对象,并且不能丢弃。
但
这个类将很好地处理不基于对象标识(例如字符串实例)的等于方法的关键对象。然而,对于这样的可重新创建的密钥对象,自动删除其键已被丢弃的WeakHashMap条目可能会令人困惑。
https://stackoverflow.com/questions/48411077
复制相似问题