-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconcurrentHashMap.txt
94 lines (91 loc) · 4.33 KB
/
concurrentHashMap.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
ConcurrentModification Exception and concurrentHashMap-
Java collection classes are fail fast, which means if collection will be changed while some thread is traversing over it using iterator(), ConcurrentModification Exception occurs.
Ex-
Iterator<String> it = myList.iterator(); //myList is a list
while(it.hasNext()){
String value = it.next();
System.out.println("List Value:"+value);
if(value.equals("3")) myList.remove(value);
//when value=3, this line will throw the concurrentmodification exception
}
Concurrent modification exception can occur in case of multithreaded as well as single threaded java programming environment.
To Avoid ConcurrentModificationException in multi-threaded environment-
There are 3 ways to avoid this exception-
1) You can convert the list to an array and then iterate on the array. This approach works well for small or medium size list but if the list is large then it will affect the performance a lot.
2) You can lock the list while iterating by putting it in a synchronized block. This approach is not recommended because it will cease the benefits of multithreading.
3) If you are using JDK1.5 or higher then you can use ConcurrentHashMap and CopyOnWriteArrayList classes. This is the recommended approach to avoid concurrent modification exception.
To Avoid ConcurrentModificationException in single-threaded environment-
You can use the iterator remove() function to remove the object from underlying collection object. But in this case you can remove the same object and not any other object from the list.
Ex-
package com.journaldev.java;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
public class ThreadSafeIteratorExample {
public static void main(String[] args) {
List<String> myList = new CopyOnWriteArrayList<String>();
myList.add("1");
myList.add("2");
myList.add("3");
myList.add("4");
myList.add("5");
Iterator<String> it = myList.iterator();
while(it.hasNext()){
String value = it.next();
System.out.println("List Value:"+value);
if(value.equals("3")){
myList.remove("4");
myList.add("6");
myList.add("7");
}
}
System.out.println("List Size:"+myList.size());
Map<String,String> myMap = new ConcurrentHashMap<String,String>();
myMap.put("1", "1");
myMap.put("2", "2");
myMap.put("3", "3");
Iterator<String> it1 = myMap.keySet().iterator();
while(it1.hasNext()){
String key = it1.next();
System.out.println("Map Value:"+myMap.get(key));
if(key.equals("1")){
myMap.remove("3");
myMap.put("4", "4");
myMap.put("5", "5");
}
}
System.out.println("Map Size:"+myMap.size());
}
}
Output of above program is written below. There is no ConcurrentModificationException being thrown by the program.
output-
List Value:1
List Value:2
List Value:3
List Value:4
List Value:5
List Size:6
Map Value:1
Map Value:2
Map Value:4
Map Value:5
Map Size:4
so,
1) Concurrent Collection classes can be modified safely, they will not throw ConcurrentModificationException.
2) In case of CopyOnWriteArrayList, iterator doesn’t accommodate the changes in the list and works on the original list.
3) In case of ConcurrentHashMap, the behaviour is not always the same.
So if you are using ConcurrentHashMap then avoid adding new objects as it can be processed depending on the keyset. Note that the same program can print different values in your system because HashMap keyset is not ordered.
Alternative Approach:
If you are working on single-threaded environment and want your code to take care of the extra added objects in the list then you can do so using for loop rather than iterator.
Ex-
for(int i = 0; i<myList.size(); i++){
System.out.println(myList.get(i));
if(myList.get(i).equals("3")){
myList.remove(i);
i--;
myList.add("6");
}
}
We are decreasing the counter because we are removing the same object, if you have to remove the next or further far object then you don't need to decrease the counter. You will get ConcurrentModificationException if you will try to modify the structure of original list with subList. Structural modifications is allowed only on the list returned by subList method, otherwise ConcurrentModificationException will occur.