0

I am trying to test concurrent puts to a ConcurrentHashMap using multiple threads, but the size of the map after processing is not what I expected.

I have the following code to insert 1000 entries into a ConcurrentHashMap:

@Test
public void testThreadSafetyConcurrentHashMap() {
    Map<Integer, Integer> map = new ConcurrentHashMap<>();

    Runnable runnable = () -> {
        for (int i = 0; i < 1000; i++) {
            map.put(i, i);
        }
    };

    ExecutorService executorService = Executors.newFixedThreadPool(4);
    for (int i = 0; i < 4; i++) {
        executorService.submit(runnable);
    }

    System.out.println(map.size());
}

I am expecting 1000 items for the map.size() call, but I don't get this every time.

Can someone tell me what the problem is? I thought 4 threads putting 1000 items at the same time, would result in a total of 1000 items at the end?

2
  • 2
    Are all the runnables done by the time you print the map's size?
    – f1sh
    Commented Nov 2, 2022 at 18:22
  • 2
    You immediately print the size after starting the threads. They're simply not finished in the short amount of time. Try adding a Thread.sleep(1000); before printing and you'll see.
    – QBrute
    Commented Nov 2, 2022 at 18:22

1 Answer 1

6

You can use ExecutorService.invokeAll() to ensure that all threads are done with their job before the size of the map would be checked.

This method returns "a list of Futures holding their status and results when all complete", i.e. it is blocking and that's what we need in this case (we are not interested in its return value and it's omitted in the code below).

invokeAll() expects a collection of Callable and we can use Executors.callable() to convert a Runnable into a Callable.

Map<Integer, Integer> map = new ConcurrentHashMap<>();
    
Runnable runnable = () -> {
    for (int i = 0; i < 1000; i++) {
        map.put(i, i);
    }
};
    
ExecutorService executorService = Executors.newFixedThreadPool(4);

executorService.invokeAll(Collections.nCopies(4, Executors.callable(runnable)));
    
System.out.println(map.size());

Not the answer you're looking for? Browse other questions tagged or ask your own question.