Non thread safe performance of HashMap

Posted by Otoom on Sun, 23 Jan 2022 07:22:50 +0100

preface

We all know that HashMap is thread unsafe, but what are the specific manifestations?

Example 1 dead cycle

This is the most frequently asked question in an interview, but in fact, this question has been asked in Java 1 Version 8 has been fixed. This problem exists only before version 1.7.
The general reason is that when HashMap is expanded, the linked list adopts header insertion method, which will reverse the order of the linked list. If two threads expand at the same time, a circular linked list will appear in a certain scenario, resulting in an endless loop. There are many articles on the Internet, There is an article Well written, no more repetition

java1. The repair method is to change the head insertion method to the tail insertion method to avoid this dead cycle problem. reference resources article , you can also take a look at the code of resize, which is easy to understand.

So java1 8 will there be no dead cycle problem? No, it is still possible to cause an endless loop when multithreading the red black tree. Refer to article However, the specific reasons for this place are not found in a detailed article to be proved.

Example 2 hash conflict causes overwrite

Scenario: if the current capacity of an empty HashMap is 8 and the two threads put in data with key=1 and key=9 respectively, in some scenario, only one value may be passed in and the size will increase by 2.
The code is as follows, which requires one-step debugging

	public static void main(String[] args) throws InterruptedException {
        final HashMap<Integer, String> hashMap = new HashMap<>(8);

        CountDownLatch countDownLatch = new CountDownLatch(2);
        new Thread(() -> {
            hashMap.put(1, "1");
            countDownLatch.countDown();
        }).start();

        new Thread(() -> {
            hashMap.put(9, "9");
            countDownLatch.countDown();
        }).start();

        countDownLatch.await();
    }

The two breakpoints are as follows for multi-threaded debugging (idea breakpoint type and multi-threaded debugging can be searched on the Internet)

Make both threads go to this line of code, then execute the following code respectively and return to the main method.

Finally, you will find that the HashMap size=2, but there is only one element.

The reason is that HashMap uses an array of nodes to save elements. Node s with the same hash value will be placed in the same position of the array, and then the zipper method or red black tree will be used to save elements.
When there is no element at an index of the array, an element will be initialized and assigned to the index of the array. If the hash values of the elements placed by the two threads are the same, and both threads find that there is no value at the index, they will initialize a value and then assign a value. At this time, they will overlap each other. So in the end, only one element is put into the HashMap, and the other becomes garbage waiting to be recycled

generality

In fact, to explain that HashMap threads are unsafe, there are many manifestations, but it is not necessary to list them one by one.

Previously written article It has been said in: the essential reason for thread insecurity is that there are race conditions. When the modification of shared resources cannot be atomized and sensitive to order, it will lead to thread insecurity. This is the root cause of all the above situations, but the manifestations are different.

Therefore, basically mastering this essence, you can analyze all thread unsafe situations.

HashTable

As we know, HashTable is thread safe. It adds synchronized to all methods.

  • Can this method achieve thread safety? sure
  • What is the principle of this method? The principle is that synchronized needs to obtain the lock of the current instance, and static synchronized needs to obtain the lock of the current class. As for further details, I don't know how to implement the instructions such as monitorenter and monitorexit.
  • Are the two methods modified by synchronized and static synchronized synchronized synchronized? No, because the locks to be acquired are different. As shown in the following code, func1 and func4 are synchronized, and func2 and func3 are synchronized. Breakpoint debugging will find that when one thread obtains the lock, another thread will enter the MONITOR state to wait for the lock when trying to obtain the lock.
import java.util.HashMap;
import java.util.concurrent.CountDownLatch;

public class H {
    public static synchronized void func1() {
        System.out.println("func1");
    }

    public synchronized void func2() {
        System.out.println("func2");
    }

    public void func3() {
        synchronized (this) {
            System.out.println("func3");
        }
    }

    public void func4() {
        synchronized (H.class) {
            System.out.println("func4");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        H h = new H();
        new Thread(() -> {
            h.func1();
        }).start();
        new Thread(() -> {
            h.func2();
        }).start();
        new Thread(() -> {
            h.func3();
        }).start();
        new Thread(() -> {
            h.func4();
        }).start();

        CountDownLatch countDownLatch = new CountDownLatch(1);
        countDownLatch.await();
    }
}

  • What is the problem with the implementation of HashTable? The problem is obvious. The granularity of locking is too coarse. If we only need to lock where race conditions occur for thread safety, we don't need to lock all the code, which will lead to poor performance.

ConcurrentHashMap

We know that we must use ConcurrentHashMap under multithreading. But how is it thread safe? This is still very interesting.

There is an article How does ConcurrentHashMap achieve thread safety Well written
And a public official account is good.
Source code analysis of ConcurrentHashMap for java collection (1)
Source code analysis of ConcurrentHashMap for java collection (2)
Analysis of the source code of ConcurrentHashMap for java collection (3)

Wait for yourself to run through the code..

Topics: Java HashMap