Interviewer: Why does HashMap under concurrency cause an infinite loop?

When I was studying Java concurrent containers and frameworks today, when I saw why ConcurrentHashMap was used, one of the reasons was: thread-unsafe HashMap, HashMap will cause an infinite loop when concurrently performing put operations, because multithreading will lead to HashMap Entry The linked list forms a circular data structure, and the search will fall into an infinite loop. I have read other blogs for the reason, and they are all abstract, so I will show it in a graphic way here, I hope to support it!

(1) When adding elements to the HashMap, it will cause the expansion of the HashMap container. The principle is not explained, and the source code is directly attached, as follows:

(2) Referring to the above code, the transfer method is introduced, (important point) This is the root cause of the infinite loop when HashMap is concurrent. The following combines the source code of transfer to explain the principle of the infinite loop, first listed The transfer code (this is the source of JDK7) is as follows:

(3) Assumptions:

Map<Integer> map = new HashMap<Integer>(2);  // 只能放置两个元素,其中的threshold为1(表中只填充一个元素时),即插入元素为1时就扩容(由addEntry方法中得知)
//放置2个元素 3 和 7,若要再放置元素8(经hash映射后不等于1)时,会引起扩容

Suppose the placement result graph is as follows:

Now there are two threads A and B, both of which must perform the put operation, that is, add elements to the table, that is, both thread A and thread B will see the state snapshot of the above figure.

The order of execution is as follows:

Execution 1: Thread A executes to the transfer function and suspends at (1) (the transfer function code is marked). At this point in the stack of thread A

Execution 2: Thread B executes the while loop in the transfer function, which will turn the original table into a new table (in thread B's own stack), and then write it into memory. As shown in the figure below (assuming that the two elements are also mapped to the same position under the new hash function)

Execution 3: Thread A unhooks, and then executes (the old table is still seen), that is, it executes from the transfer code (1), the current e = 3, next = 7, as described above.

1. Process element 3, put 3 into the new table of thread A's own stack (the new table is in thread A's own stack, private to the thread and not affected by thread 2), the picture after processing 3 is as follows:

2. Thread A copies element 7 again, the current e = 7, and the next value is 3 because thread B modifies its reference, so the new table after processing is as follows

3. Since the next = 3 obtained above, the while loop is followed, that is, the currently processed node is 3, next is null, and the while loop is exited. After the while loop is executed, the contents of the new table are as follows:

4. When the operation is completed and the search is performed, it will fall into an infinite loop!

Guess you like

Origin blog.csdn.net/m0_63437643/article/details/123774093