我知道java Hashmap有一个容量和加载因子参数。所以,如果这个hashmap中的项目数超过capacity * load factor,那么将重建一个新的hashmap。我对重构的问题有一些疑问。它:
答案 0 :(得分:9)
如果重建发生,前一个hashmap将被回收或仍然在使用?
它仍然是相同的散列图,只是内部存储被重建。在重建之后,不再需要旧的桶阵列,并且可以是gc&#39。
更新:内部HashMap
有Node<K,V>[] table
。在调整大小期间,将构造一个新数组,移动元素,然后用新数组替换table
。在该操作之后,映射本身将不再引用旧数组,因此除非没有其他引用(由于table
不是由于包私有),否则它对于gc是可以接受的。
因为我们需要一个更大的hashmap,所以,哈希函数会被改变吗?
不,哈希函数不会改变。它通常不依赖于桶的数量,但生成的散列将被调整以获得正确的桶(例如,通过应用模数)
更新:HashMap
计算存储区索引,如下所示:(size - 1) & hash
,hash
是密钥hashCode()
的返回值方法,它不依赖于地图本身。
对于ConcurrentHashMap,如果一个线程正在插入(对于cource,这个插入操作导致重构)并且另一个线程正在读取怎么办?例如,它将从旧的hashmap或新的hashmap读取? / p>
我必须在这里猜测(我稍后会查看代码)但我认为只要线程正在从旧存储桶中读取它们,它们仍将被使用并将被释放后面。
更新:我快速浏览了ConcurrentHashMap
来源,并提及table
使用的当前get()
和nextTable
{1}}这是调整大小操作的目标。在调整大小期间,元素将传输到nextTable
,最后table
设置为nextTable
,从而有效地切换表格。
这意味着在调整大小期间仍会读取旧表,并且在某些时候它会被替换。在插入操作期间,可能是一些阻塞,例如通过使用synchronized块,特别是在需要调整大小或已经执行调整大小时。
文档还提示:
支持检索完全并发和更新的高预期并发性的哈希表。
这意味着get
不会阻止put
,remove
等等。可能在某个时候阻止。
答案 1 :(得分:2)
1)
HashMap的一个实例有两个影响其性能的参数:初始容量和负载因子。容量是哈希表中的桶数,初始容量只是创建哈希表时的容量。加载因子是在自动增加容量之前允许哈希表获取的完整程度的度量。 当哈希表中的条目数超过加载因子和当前容量的乘积时,哈希表将被重新哈希(即,重建内部数据结构),以便哈希表的数量大约是哈希表的两倍。水桶。
2)如果你事先知道大小,那么在构建地图对象时更好地创建hashbuckets。
HashMap(int initialCapacity)
答案 2 :(得分:0)
如果重建发生,前一个hashmap将被回收或仍然在使用?
如果没有对先前结构的引用,则可以对它们进行垃圾回收。
因为我们需要一个更大的hashmap,所以,哈希函数会被改变吗?
不完全是。哈希仍然是相同的,只有哈希映射到桶的方式才会改变。例如,在扩展之前,散列27,103和32,504可以映射到同一个桶。扩展后,他们可能会映射到不同的桶。哈希映射将在每个存储桶中拥有更多存储桶和更少的元素。
对于ConcurrentHashMap,如果一个线程正在插入(对于cource,这个插入操作会导致重构)并且另一个线程正在读取怎么办?例如,它将从旧的hashmap或新的hashmap读取吗?
如果您在意,那么您必须使用锁。您使用ConcurrentHashMap是因为您需要并发。如果要在读取和写入之间进行可预测的排序,则必须对它们进行排序。即使没有重建也是如此。如果您同时进行读写操作,则读取可能反映也可能不反映写入。如果在一个线程中写入并在该写入返回之前从另一个线程发出读取,则读取可能反映也可能不反映写入。 ConcurrentHashMap为您提供了理智的结果,但没有强制执行排序(怎么可能?)。
答案 3 :(得分:0)