1. HashMap data structure
The jdK8 data structure is array + linked list
Jdk8 and later data structures are arrays + linked lists + red-black trees
Avoid using HashMap in a concurrent environment because it is possible to create a looped linked list when capacity expansion occurs, which can cause 100% CPU problems when performing get
2. Why does HashMap choose array + linked list + red-black tree data structure
- Array: the storage and retrieval efficiency is the highest, time complexity is
O(1)
- Linked list: To solve the hash collision problem, the search operation needs to traverse all data in the linked list, and the time complexity is
O(n)
- Red-black tree: optimizes the performance of linked lists. The time complexity of operations such as search, insert, and delete is
O(logN)
3. Why not use a red-black tree instead of switching to a red-black tree after the chain expression reaches a specified length?
If the number of elements is small, the efficiency of red-black tree is not as good as that of linked list, and the balance of red-black tree is broken, and spin (left and right) is needed to maintain the self-balance of the tree
4, linked list to red black tree threshold is the origin and linked list to red black tree conditions
Origin of the threshold: The threshold for converting a linked list to a red-black tree is calculated by the probability of the poisson distribution (probability statistics) appearing a list of (1 element, 2 elements, 3 elements)
Conversion condition: The conversion is performed only when the array length is greater than or equal to 64 and the list length of an array element is greater than or equal to 9
5. Why is it possible to convert an array to a red-black tree if the array length reaches 64?
final void treeifyBin(Node<K,V>[] tab, int hash) {
int n, index; Node<K,V> e;
// Todo arrays with a length less than 64 will not be converted to a red-black tree
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
resize();
else if ((e = tab[index = (n - 1) & hash]) ! =null) {
TreeNode<K,V> hd = null, tl = null;
do {
TreeNode<K,V> p = replacementTreeNode(e, null);
if (tl == null)
hd = p;
else {
p.prev = tl;
tl.next = p;
}
tl = p;
} while((e = e.next) ! =null);
if((tab[index] = hd) ! =null) hd.treeify(tab); }}Copy the code
6. Why is the threshold for list to red black tree 9 instead of 8?
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
//todo initializes the size
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
// Todo hashes to determine if the array element has a value
if ((p = tab[i = (n - 1) & hash]) == null)
// Todo does not insert elements directly
tab[i] = newNode(hash, key, value, null);
else {
//todo note that there is already one element in the array element corresponding to the hash value
Node<K,V> e; K k;
//todo checks whether the key exists and overwrites the old value
if(p.hash == hash && ((k = p.key) == key || (key ! =null && key.equals(k))))
e = p;
//todo determines whether it is a red-black tree
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
//todo enters the list logic
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
//todo creates a Node
p.next = newNode(hash, key, value, null);
// If the list length is greater than or equal to 7, loop 8 times to create 8 nodes, plus the existing node, the list length is 9 before the red-black tree conversion
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if(e.hash == hash && ((k = e.key) == key || (key ! =null && key.equals(k))))
break; p = e; }}if(e ! =null) { // existing mapping for key
V oldValue = e.value;
if(! onlyIfAbsent || oldValue ==null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
Copy the code
7. Why does HashMap recommend an array with a power of 2
Capacity initialization: The incoming capacity is not an exponential power of 2 and is converted to the nearest exponential power of 2 greater than that number
In order to improve efficiency, the efficiency of hashcode%length modulus is low, and the efficiency of bit operation hashcode&(leng-1) is high. Jdk1.7 array expansion will generate a large number of Rehashes
8. Why is the load factor 0.75?
To solve the hash collision problem
- If the load factor is greater than or equal to
1
, the collision probability is higher, the linked list length is longer, the search time complexity is higher (time space) - If the load factor is less than or equal to
0.5
, fast query (space for time), low hash collision
The value 0.75 is based on Newton binomial overthrown out, in time and space for compromise processing