The following piece of code does not work as expected. When I call put method in Does class the value in the concurrent hash map is associated with different instances of map. So what I am trying to do is multiple threads access the same map and insert a value for the same key. However if I add a synchronized keyword to the put method it works. What am I missing?
class Does implements Runnable {
C2 c2;
Does(C2 c2) {
this.c2 = c2;
}
public void run() {
c2.put("Hello");
}
}
public class C2 {
public ConcurrentHashMap<String, List<String>> map = new ConcurrentHashMap<String, List<String>>();
public static void main(String args[]) {
C2 c2 = new C2();
new Thread(new Does(c2)).start();
new Thread(new Does(c2)).start();
new Thread(new Does(c2)).start();
new Thread(new Does(c2)).start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
List<String> lu = c2.map.get("Hello");
System.out.println(lu);
}
/**
* @param string
*/
public void put(String string) {
if (map.containsKey(string)) {
List<String> li = map.get(string);
li.add("adding something");
} else {
List<String> li = new ArrayList<String>();
li.add("adding something");
map.put(string, li);
}
}
}
Appreciate the help.
This code is not thread safe
public void put(String string) {
if (map.containsKey(string)) {
// anything can happen in another thread here
List<String> li = map.get(string);
// anything can happen in another thread here
li.add("adding something");
} else {
// anything can happen in another thread here
List<String> li = new ArrayList<String>();
li.add("adding something");
// anything can happen in another thread here
map.put(string, li);
}
In Java 8 you can use computeIfAbsent.
public void put(String string) {
// all most thread safe.
map.computeIfAbsent(string, k -> new ArrayList<>())
.add("add something");
}
Note this is still not thread safe as the ArrayList is not thread safe, so what you need is
public void put(String string) {
List<String> list = map.computeIfAbsent(string, k -> new ArrayList<>());
synchronized(list) {
list.add("add something");
}
}