This generally comes when use for each loop
Example
package mypackage;
import java.util.ArrayList;
import java.util.List;
public class my {
public static void main(String[] args) {
List<String> ls = new ArrayList<>();
ls.add("1");
ls.add("2");
ls.add("3");
for (String ok:ls) {
if (ok.equals("2")) {
ls.add("5");
ls.remove("5");
}
}
System.out.println(ls);
}
}
Example
package mypackage;
import java.util.ArrayList;
import java.util.List;
public class my {
public static void main(String[] args) {
List<String> ls = new ArrayList<>();
ls.add("1");
ls.add("2");
ls.add("3");
for (String ok:ls) {
if (ok.equals("2")) {
ls.add("5");
ls.remove("5");
}
}
System.out.println(ls);
}
}
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at mypackage.my.main(my.java:16)
But it would run fine when we use normal For Loop
package mypackage;
import java.util.ArrayList;
import java.util.List;
public class my {
public static void main(String[] args) {
List<String> ls = new ArrayList<>();
ls.add("1");
ls.add("2");
ls.add("3");
for (int i = 0; i < ls.size(); i++) {
if (ls.get(i).equals("2")) {
ls.add("5");
ls.remove("5");
}
}
System.out.println(ls);
}
}
Output
[1, 2, 3]
Synchronization of ArrayList in Java
Implementation of arrayList is not synchronized is by default. It means if a thread modifies it structurally and multiple threads access it concurrently, it must be synchronized externally.
1. Why are almost collection classes not thread-safe?
Do you notice that all the basic collection classes - ArrayList, LinkedList, HashMap, HashSet, TreeMap, TreeSet, etc - all are not synchronized? In fact, all collection classes (except Vector and Hashtable) in the java.util package are not thread-safe.
The only two legacy collections are thread-safe: Vector and Hashtable. WHY?
Here’s the reason: Synchronization can be very expensive!
2. Using CopyOnWriteArrayList.
When using the iterator of a synchronized collection, we should use synchronized block to safeguard the iteration code because the iterator itself is not thread-safe.
Synchronization of ArrayList in Java
Implementation of arrayList is not synchronized is by default. It means if a thread modifies it structurally and multiple threads access it concurrently, it must be synchronized externally.
1. Why are almost collection classes not thread-safe?
Do you notice that all the basic collection classes - ArrayList, LinkedList, HashMap, HashSet, TreeMap, TreeSet, etc - all are not synchronized? In fact, all collection classes (except Vector and Hashtable) in the java.util package are not thread-safe.
The only two legacy collections are thread-safe: Vector and Hashtable. WHY?
Here’s the reason: Synchronization can be very expensive!
Vector and Hashtable quickly expose poor performance in multi-threaded programs. As you may know, synchronization requires locks which always take time to monitor, and that reduces the performance.
That’s why the new collections (List, Set, Map, etc) provide no concurrency control at all to provide maximum performance in single-threaded applications.
How Does Concurrent Modification Occurs in Multi Threading
public class IteratorFailFastTest {
private List<Integer> list = new ArrayList<>();
//Constructor to make multiple adds in list using for loop
public IteratorFailFastTest() {
for (int i = 0; i < 10_000; i++) {
list.add(i); // adding elements here
}
}
public void runUpdateThread() {
Thread thread1 = new Thread(new Runnable() {
public void run() {
for (int i = 10_000; i < 20_000; i++) {
list.add(i); // adding elements here
}
}
});
thread1.start();
}
public void runIteratorThread() {
Thread thread2 = new Thread(new Runnable() {
public void run() {
ListIterator<Integer> iterator = list.listIterator();
while (iterator.hasNext()) {
Integer number = iterator.next();
System.out.println(number);
}
}
});
thread2.start();
}
public static void main(String[] args) {
IteratorFailFastTest tester = new IteratorFailFastTest();
tester.runIteratorThread(); // adding
tester.runUpdateThread(); //iterating
}
}
Note:
As you can see, the thread1 is iterating the list, while the thread2 adds more elements to the collection. This causes the ConcurrentModificationException to be thrown.
Solution
As you can see, the thread1 is iterating the list, while the thread2 adds more elements to the collection. This causes the ConcurrentModificationException to be thrown.
Solution
There are two way to create Synchronized Arraylist.
1. Collections.synchronizedList() method.
2. Using CopyOnWriteArrayList.
Example
Collections.synchronizedList() method.
public class my {
public static void main(String[] args) {
List<String> ls=Collections.synchronizedList(new ArrayList<String>());
ls.add("Name");
ls.add("Hello");
ls.add("Hi");
ls.add("Cool");
ls.add("Good");
synchronized (ls)
{
Iterator<String> iterator = ls.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
System.out.println(next);
}
}
}
}
When using the iterator of a synchronized collection, we should use synchronized block to safeguard the iteration code because the iterator itself is not thread-safe.
Example
Using CopyOnWriteArrayList.
It achieves thread-safety by creating a separate copy of List
It is costly as involves separate Array copy with every write operation(e.g. add, set, remove..)
It is very efficient when you have List and need to traverse over its elements and don’t modify often it.
Iterator does not throw ConcurrentModificationException even if copyOnWriteArrayList is modified once iterator is created because iterator is iterating over the separate copy of ArrayList while write operation is happening on another copy of ArrayList.
public static void main (String[] args)
{
// creating a thread-safe Arraylist.
CopyOnWriteArrayList<String> threadSafeList
= new CopyOnWriteArrayList<String>();
// Adding elements to synchronized ArrayList
threadSafeList.add("geek");
threadSafeList.add("code");
threadSafeList.add("practice");
System.out.println("Elements of synchronized ArrayList :");
// Iterating on the synchronized ArrayList using iterator.
Iterator<String> it = threadSafeList.iterator();
while (it.hasNext())
System.out.println(it.next());
}
Good Reads
http://www.codejava.net/java-core/concurrency/java-concurrent-collection-copyonwritearraylist-examples
https://www.geeksforgeeks.org/synchronization-arraylist-java/
https://www.quora.com/in/How-do-I-make-Arraylist-threadsafe
https://www.geeksforgeeks.org/synchronization-arraylist-java/
https://www.quora.com/in/How-do-I-make-Arraylist-threadsafe
ConcurrentHashMap
- You should use ConcurrentHashMap when you need very high concurrency in your project.
- It is thread safe without synchronizing the whole map.
- Reads can happen very fast
No comments:
Post a Comment