假设有2个线程,两个线程都在同一个HashMap的Hashtable上工作。
线程T1通过调用map.get()而不是迭代来读取,而线程T2将对象放在ConcurrentHashMap的相同HashTable中。
现在,如果达到阈值级别,则T2将尝试调整Concurrent HashMap中的Hashtable的大小。 那么,T1是否会被阻止读取,还是会从旧的缓存结构中读取?
答案: 我假设作为值和条目类的条目是易变的它将直接从主存储器给我们最后更新的值。 没有脏读或缓存读数。
我读过许多博客甚至是java doc,但没有一个为这种情况提供明确的答案。让我知道你的意见。
答案 0 :(得分:2)
来自docs:
检索操作(包括get)一般不会阻塞,所以可能 与更新操作重叠(包括put和remove)。的反演 反映最近完成的更新操作的结果 坚持发病。 (更正式地说,一个更新操作 给定密钥与任何(非空)检索之前的关系 用于该密钥报告更新的值。)用于聚合操作 例如putAll和clear,并发检索可能反映插入 或删除只有一些条目。 同样,Iterators,Spliterators 和Enumerations返回反映哈希状态的元素 表格在创建时或之后的某个时刻 迭代器/枚举即可。他们不 抛出ConcurrentModificationException。但是,迭代器是设计好的 一次只能由一个线程使用。
因此,如果你正在迭代ConcurrentHashMap
实例而另一个线程修改它,那么没有什么不好的事情会发生,你的线程也会被阻塞,你只会看到一些较旧的快照。
另见:
答案 1 :(得分:0)
这是我的理解:
在重新哈希期间,段被锁定并且新表在旧表旁边构建,然后删除该旧表,并更新哈希码生成器以提供最新的哈希码,该哈希码将指向新创建的段。
因此,hascode生成器可以为读取器线程提供旧段或新段的ID。
如果阅读器线程的ID为新细分,则意味着已经完成了调整大小。所以这里没问题。
如果读者线程的ID为旧段,那么我们有两种可能性:
1.读取器线程在段中找到值,这意味着调整大小线程可能仍在构造新段。
2.在读者线程检查该段之前,调整程序线程开始创建新表,并且哈希码生成器已更新,以便下一次读取操作将从该新位置获取哈希码。现在,调整大小操作开始删除旧的段记录。
现在读取器线程仍然具有旧的段地址,并且现在已计划运行该段地址,因此它将获得空值,因此在这种情况下,调用将获得被阻止,该值将被重新读取。 我们可以假设,读取器线程刚刚联系了哈希码生成器,并发现调整大小后,读取器线程将必须获取新的哈希码。