Reputation: 351
I have seen this code in the book Java 7 recipes to update and iterate a Map concurrently:
ConcurrentMap<Integer,String> concurrentMap = new ConcurrentHashMap<Integer, String>();
for (int i =0;i < 1000;i++) {
startUpdateThread(i, concurrentMap);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (Map.Entry<Integer, String> entry : concurrentMap.entrySet()) {
System.out.println("Key :"+entry.getKey()+" Value:"+entry.getValue());
}
And the method to update the map as follows:
private void startUpdateThread(int i, final ConcurrentMap<Integer, String> concurrentMap) {
Thread thread = new Thread(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
int randomInt = random.nextInt(20);
concurrentMap.put(randomInt, UUID.randomUUID().toString());
}
} });
thread.setName("Update Thread "+i);
updateThreads.add(thread);
thread.start();
}
I have tried with just a HashMap instead of ConcurrentHasMap and the results are the same (monitored with Java VisualVM). Does anyone know why?
Thanks, Agustin
UPDATE: A few interesting questions:
Upvotes: 0
Views: 179
Reputation: 5622
ConcurrentHashMap
allows for multiple-thread access, in contrast to HashMap
which does not.
Calling HashMap#put
from multiple threads at the same time may break your map. ConcurrentHashMap
handles those scenarios and mitigates race conditions.
As for your test in particular, your map only has 20 keys which means it will get full relatively quickly. The weak spot for hashmap is when you need to expand the bucket space and at the same time put another entry. Try increasing the amount of keys to Integer.MAX_VALUE
and you will have a much higher chance to see it breaking.
Upvotes: 2
Reputation: 16516
The code below will give you a different result. The reason why your code does not crash is a small random interval of 20 integers. So your map gets full instantly and after this it's key set is not being modified. I changed the random interval to 10000 and added sleeps, so now it's being continuously updated during the program run and crashes for HashMap
. And it works for ConcurrentHashMap
which is capable to iterate over the data which is being modified.
public class Test {
static List<Thread> threadList = new ArrayList<>();
public static void main(String[] args) throws InterruptedException {
Map<Integer,String> map = new HashMap<>();
for (int i =0;i < 1000;i++) {
startUpdateThread(i, map);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println("Key :"+entry.getKey()+" Value:"+entry.getValue());
}
for (Thread thread : threadList) {
thread.interrupt();
}
}
private static void startUpdateThread(int i, final Map<Integer, String> concurrentMap) {
Thread thread = new Thread(new Runnable() {
public void run() {
Random random = new Random();
while (true) {
int randomInt = random.nextInt(10000);
concurrentMap.put(randomInt, UUID.randomUUID().toString());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
return;
}
}
} });
threadList.add(thread);
thread.setName("Update Thread " + i);
thread.start();
}
}
Upvotes: 1