ArrayList is a very useful Collection in Java, I guess most used one as well but it is not synchronized. What this mean? It means you cannot share an instance of ArrayList between multiple threads if they are not just reading from it but also writing or updating elements. So how can we synchronize ArrayList? Well, we'll come to that in a second but did you thought why ArrayList is not synchronized in the first place? Since multi-threading is a core strength of Java and almost all Java programs have more than one thread, why Java designer does not make it easy for ArrayList to be used in such an environment?
The answer lies in performance, there is a performance cost associated with synchronization, and making ArrayList synchronized would have made it slower. So, they definitely thought about it and left ArrayList as non-synchronized to keep it fast, but at the same time they have provided easy ways to make it synchronized and this is what we are going to learn in this tutorial.
The JDK Collections class has several methods to create synchronized List, Set and Map and we will use Collections.synchronizedList() method to make our ArrayList synchronized. This method accepts a List which could be any implementation of the List interface e.g. ArrayList, LinkedList, and returns a synchronized (thread-safe) list backed by the specified list. So you can also use this technique to make LinkedList synchronized and thread-safe in Java.
For curious readers, I also suggest taking a look at Core Java Volume 1 - Fundamentals by Cay S. Horstmann. One of the better and up-to-date books on Java programming.
For curious readers, I also suggest taking a look at Core Java Volume 1 - Fundamentals by Cay S. Horstmann. One of the better and up-to-date books on Java programming.
Synchronized List and Iteration
One of the main challenges of sharing ArrayList between multiple threads is how to deal with a situation where one thread is trying to access the element which is removed by other. If you are using methods like get(index) or remove(index) method to retrieve or remove elements then it's also possible that other thread may also be removing other elements.This means you cannot call get(index) or remove(index) reliably without checking the size of the list first and then you also needs to provide extra synchronization between your call to size() and remove(int index).
In order to guarantee serial access, it is critical that all access to the backing list is accomplished through the returned list and it is imperative that the user manually synchronizes on the returned list when iterating over it as shown in the following sample code :
List list = Collections.synchronizedList(new ArrayList());
As suggested in Java documentation, failure to follow this advice may result in non-deterministic behavior. Also the list will be serializable if the provided ArrayList is serializable. See Core Java Volume 1 - Fundamentals by Cay S. Horstmann. One of the better and up-to-date book on Java programming.
You can now safely share this list among multiple threads, but you need to be a little bit careful while retrieving or removing elements from ArrayList. In order to have safe access, you should use Iterator for getting and removing elements from the list and that too in a synchronized manner as shown in this example.
That's all on how to synchronize ArrayList in Java. As you have learned it's very easy to do that in Java because of the Collections.synchronizedList() method but you need to be a little bit more careful while retrieving and removing objects from List. By the way, there are couple more options available to you in form of Vector and CopyOnWriteArrayList.
Vector is a very old class but was retrofitted to implement the List interface in Java 1.4 and more importantly it is synchronized so you don't need to synchronize it again. By the way, while using Vector make sure you use it via the List interface and not by using legacy methods, otherwise you won't be able to replace the implementation later.
On the other hand, CopyOnWriteArrayList is part of concurrent collection classes in Java and much more scalable than both Vector and ArrayList. If your program mostly reads from List and occasionally updates it, this could be the right choice.
In order to guarantee serial access, it is critical that all access to the backing list is accomplished through the returned list and it is imperative that the user manually synchronizes on the returned list when iterating over it as shown in the following sample code :
List list = Collections.synchronizedList(new ArrayList());
... synchronized(list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); }
As suggested in Java documentation, failure to follow this advice may result in non-deterministic behavior. Also the list will be serializable if the provided ArrayList is serializable. See Core Java Volume 1 - Fundamentals by Cay S. Horstmann. One of the better and up-to-date book on Java programming.
Java Program to Synchronize ArrayList
Here is the complete example of synchronizing an ArrayList in Java. If you look, we have created a List of String and added a couple of elements to it. Then we passed this ArrayList to Collections.synchronizedList() method, which returned a thread-safe, synchronized version of the backed list.You can now safely share this list among multiple threads, but you need to be a little bit careful while retrieving or removing elements from ArrayList. In order to have safe access, you should use Iterator for getting and removing elements from the list and that too in a synchronized manner as shown in this example.
import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * How to synchronize ArrayList in Java * * @author WINDOWS 8 */ public class SynchronizedArrayListDemo { public static void main(String args[]) { // An ArrayList which is not synchronize List<String> listOfSymbols = new ArrayList<String>(); listOfSymbols.add("RELIANCE"); listOfSymbols.add("TATA"); listOfSymbols.add("TECHMAH"); listOfSymbols.add("HDFC"); listOfSymbols.add("ICICI"); // Synchronizing ArrayList in Java listOfSymbols = Collections.synchronizedList(listOfSymbols); // While Iterating over synchronized list, you must synchronize // on it to avoid non-deterministic behavior synchronized(listOfSymbols){ Iterator<String> myIterator = listOfSymbols.iterator(); while(myIterator.hasNext()){ System.out.println(myIterator.next()); } } } } Output RELIANCE TATA TECHMAH HDFC ICICI
That's all on how to synchronize ArrayList in Java. As you have learned it's very easy to do that in Java because of the Collections.synchronizedList() method but you need to be a little bit more careful while retrieving and removing objects from List. By the way, there are couple more options available to you in form of Vector and CopyOnWriteArrayList.
Vector is a very old class but was retrofitted to implement the List interface in Java 1.4 and more importantly it is synchronized so you don't need to synchronize it again. By the way, while using Vector make sure you use it via the List interface and not by using legacy methods, otherwise you won't be able to replace the implementation later.
On the other hand, CopyOnWriteArrayList is part of concurrent collection classes in Java and much more scalable than both Vector and ArrayList. If your program mostly reads from List and occasionally updates it, this could be the right choice.
No comments:
Post a Comment
Feel free to comment, ask questions if you have any doubt.