Parallel hashmap is a security issue

I tried an example for Fail-Safe using ConcurrentHashMap

.

Below is a snippet of the sample I tried ..

ConcurrentHashMap<String, String> cMap = new ConcurrentHashMap<String, String>();
cMap.put("1", "Windows Phone");
cMap.put("2", "iPhone");
cMap.put("3", "HTC");

Iterator iterator=cMap.keySet().iterator();

while (iterator.hasNext()) {
    System.out.println(cMap.get(iterator.next()));
    cMap.put("Samsung", "S5");
}

      

Output:

Windows Phone
HTC
iPhone

      

This is an example of fault tolerance that I understood.

But when I tried the example below, I get different output.

ConcurrentHashMap<String, String> cMap = new ConcurrentHashMap<String, String>();
cMap.put("1", "Windows Phone");
cMap.put("2", "iPhone");
cMap.put("3", "HTC");

Iterator iterator=cMap.keySet().iterator();

while (iterator.hasNext()) {
    System.out.println(cMap.get(iterator.next()));
    cMap.put("4", "S5");
}

      

Output signal

Windows Phone
HTC
S5
iPhone

      

What is the difference between the above code snippets. In the second code snippet, I add cMap.put ("4", "S5"); and this is added. But in the fisrt snippet, I add cMap.put ("Samsung", "S5"); which is not added to the ConcurrentHashmap. I am making some mistake or what else could be causing this other exit.

Thanks in advance.

+3


source to share


3 answers


A parallel map, unlike a non-competitive hashmap, is not fast if you add stuff while you iterate on it.

However, there is no guarantee as to when and if the iterator (or get () method or any other read operation) will see new added / removed elements or not.

From the documentation:

Iterators and enumerations return items reflecting the state of the hash table at some point in time or after the iterator / enumeration has been created

EDIT:

The reason for the consistently different result is how the ConcurrentHashMap organizes the segments and iterates over them.

Keys are mapped to different segments based on the hash of the key:

"1" -> 15
"2" -> 0
"3" -> 6

"4" -> 5
"Samsung" -> 7


When an iterator is called, it iterates through the segments from last to first.

So at time 0, the iterator starts at segment 15, where it finds the key "1" = "Windows Phone", which is first displayed on the screen.

Then, due to the internal implementation of the iterator, it reaches the next element, which is "3" = "HTC" in segment 6.

At this point, insert "S5" is inserted. If the key is "4", it will go to segment 5, if the key "Samsung" goes to segment 7.

After submitting "HTC" for output, it looks for the next item.

When the key is "4" it goes to segment 5 and finds "4" = "S5" and sends it out.

When the key is "Samsung", the entry goes to segment 7, which has already been scanned and found by an empty iterator, so it doesn't find it and goes straight to segment 0 to retrieve "2" = "Iphone".

This explains the behavior.

+11


source


But in the fisrt snippet, I add cMap.put ("Samsung", "S5"); which is not added to the ConcurrentHashmap.

This is not true. You add it to the hashmap. Print it out later and you will see the entry is there.



However, the elements you add to the hashmap while iterating over it may or may not be iterated over by the current iterator. Your two samples demonstrate both of these behaviors.

The structs in the package java.util.concurrent

do not check for changes during iteration (which you call "fail-safe") because their target must be used concurrently. This is not even guaranteed for regular containers.

+1


source


two parallel streams simultaneously writing to ConcurrentHashMap. According to the standard ConcurrentHashMap implementation, almost 16 threads can write and read in parallel. But in the worst case, if two objects are in the same segment or section of the ConcurrentHashMap, then parallel writing is not possible.

0


source







All Articles