How to synchronize arraylist in java to make it completely thread safe in java


In this Collection framework tutorial we will learn How to synchronize arraylist in java to make it completely thread safe with examples and programs in java.



First let’s understand problem statement >
Is synchronizing ArrayList using Collections.synchronizedList is completely thread-safe in java?
Answer is No.


Because when we synchronize ArrayList using Collections.synchronizedList in java, Iterator on synchronizedArrayList won't be synchronized in java.


So, How to synchronize arraylist in java to make it completely thread safe in java >
There are 2 solutions
Solution 1 = iterator returned by synchronizedArrayList won't be synchronized, so during iteration we must keep synchronizedArrayList in synchronization block to avoid ConcurrentModificationException in java.

Solution 2 = Use CopyOnWriteArrayList, it is completely thread-safe, also Iterator & listIterator returned by CopyOnWriteArrayList are completely thread-safe in java.





Example/ Program 1 (elaborate problem statement) to show that iterator returned by synchronizedArrayList won't be synchronized, it can throw ConcurrentModificationException  in java>
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class ArrayListSynchronizationFailsExample {
   public static void main(String[] args) {
          final List<Integer> arrayList = new ArrayList<Integer>();
          final List<Integer> synchronizedArrayList;
          // Let's make arrayList synchronized
          synchronizedArrayList = Collections.synchronizedList(arrayList);
         
          //Thread 1 will add elements in synchronizedArrayList
          Thread t1 = new Thread(new Runnable() {
                 public void run() {
                       for (int i = 0; i <= 3; i++) {
                              synchronizedArrayList.add(i);
                              try {
                                     Thread.sleep(100);
                              } catch (InterruptedException e) {
                                     e.printStackTrace();
                              }
                       }
                 }
          }, "thread-1");
         
          t1.start();
          //Thread 2 will iterate on synchronizedArrayList
          Thread t2 = new Thread(new Runnable() {
                 public void run() {
                       Iterator<Integer> it = synchronizedArrayList.iterator();
                       while (it.hasNext()) {
                              try {
                                     Thread.sleep(100);
                              } catch (InterruptedException e) {
                                     e.printStackTrace();
                              }
                              System.out.println(it.next());//throws ConcurrentModificationException
                       }
                 }
          }, "thread-2");
          t2.start();
   }
}
/*OUTPUT
Exception in thread "thread-2" java.util.ConcurrentModificationException
   at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
   at java.util.ArrayList$Itr.next(Unknown Source)
   at ArrayListSynchronizationFails$2.run(ArrayListSynchronizationFails.java:43)
   at java.lang.Thread.run(Unknown Source)
*/

Let’s discuss what happened in above program >
main thread started thread-1, thread-1 added 0 (i.e. i=0) in synchronizedArrayList, then thread-1 went for sleep(100), meanwhile

main thread started thread-2, thread-2 obtained iterator on
synchronizedArrayList, then thread-2 entered while loop, then thread-2 went for sleep(100),

sleep time was up and thread-1 again entered running state and added 1 (i.e. i=1) in synchronizedArrayList, then thread-1 went for sleep(100),


sleep time was up and thread-2 again entered running state and it.next() throws ConcurrentModificationException , because arraylist was modified by thread-1 after obtaining iterator on synchronizedArrayList.





Example/ Program 2  (elaborate Solution 1) to show that iterator returned by synchronizedArrayList won't be synchronized, so during iteration we must keep synchronizedArrayList in synchronization block to avoid ConcurrentModificationException in java >
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class ArrayListSynchronizationSucceedsExample {
   public static void main(String[] args) {
          final List<Integer> arrayList = new ArrayList<Integer>();
          final List<Integer> synchronizedArrayList;
          // Let's make arrayList synchronized
          synchronizedArrayList = Collections.synchronizedList(arrayList);
          //Thread 1 will add elements in synchronizedArrayList
          Thread t1 = new Thread(new Runnable() {
                 public void run() {
                       for (int i = 0; i <= 3; i++) {
                              synchronizedArrayList.add(i);
                              try {
                                     Thread.sleep(100);
                              } catch (InterruptedException e) {
                                     e.printStackTrace();
                              }
                       }
                 }
          }, "thread-1");
          t1.start();
          //Thread 2 will iterate on synchronizedArrayList
          Thread t2 = new Thread(new Runnable() {
                 public void run() {
                       Iterator<Integer> it = synchronizedArrayList.iterator();
                       synchronized (synchronizedArrayList) { //synchronization block
                              while (it.hasNext()) {
                                     try {
                                            Thread.sleep(100);
                                     } catch (InterruptedException e) {
                                            e.printStackTrace();
                                     }
                                     System.out.println(it.next());
                              }
                       }
                      
                 }
          }, "thread-2");
          t2.start();
   }
}
/*output
0
*/

Let’s discuss what happened in above program >
main thread started thread-1, thread-1 added 0 (i.e. i=0) in synchronizedArrayList, then thread-1 went for sleep(100), meanwhile

main thread started thread-2, it obtained lock on synchronizedArrayList object, then thread-2 obtained iterator on synchronizedArrayList, then thread-2 entered while loop, then thread-2 went for sleep(100),

sleep time was up and thread-1 entered running state but add(i) method on synchronizedArrayList was synchronized(you must know that only iterator returned on synchronizedArrayList is not thread safe, rest of the methods are completely thread-safe), so thread-1 waited for thread-2 to release lock on synchronizedArrayList object,

as soon as thread-2 released lock on synchronizedArrayList object thread-1 added 1 (i.e. i=1) in synchronizedArrayList, it further completed for loop and we didn’t encountered  ConcurrentModificationException.



Example/ Program 3  (elaborate Solution 2) to show that iterator returned by CopyOnWriteArrayList will be thread-safe, so during iteration we don’t need any synchronization block and  ConcurrentModificationException will not be thrown in java >

CopyOnWriteArrayList is completely thread-safe in java. We does not need to synchronize it explicitly.
Iterator & listIterator returned by CopyOnWriteArrayList are also completely thread-safe in java.
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class CopyOnWriteArrayListSynchronizationSucceedsExample {
   public static void main(String[] args) {
          final List<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<Integer>();
          //Thread 1 will add elements in CopyOnWriteArrayList
          Thread t1 = new Thread(new Runnable() {
                 public void run() {
                       for (int i = 0; i <= 3; i++) {
                              copyOnWriteArrayList.add(i);
                              try {
                                     Thread.sleep(100);
                              } catch (InterruptedException e) {
                                     e.printStackTrace();
                              }
                       }
                 }
          }, "thread-1");
         
          t1.start();
          //Thread 2 will iterate on CopyOnWriteArrayList
          Thread t2 = new Thread(new Runnable() {
                 public void run() {
                       Iterator<Integer> it = copyOnWriteArrayList.iterator();
                       while (it.hasNext()) {
                              try {
                                     Thread.sleep(100);
                              } catch (InterruptedException e) {
                                     e.printStackTrace();
                              }
                              System.out.println(it.next());
                       }
                 }
          }, "thread-2");
          t2.start();
   }
}
/*OUTPUT
0
*/


Note : output of all above mentioned programs may vary on different machines, because of unpredictable behaviour of thread scheduler.

So in this Collection framework tutorial we learned how to synchronize arraylist in java to make it completely thread safe with examples and programs in java.



Having any doubt? or you you liked the tutorial! Please comment in below section.
Please express your love by liking JavaMadeSoEasy.com (JMSE) on facebook, following on google+ or Twitter.


RELATED LINKS>

ConcurrentModificationException, Fail-fast and Fail-safe in detail in java

Thread states/ Thread life cycle in java


Acquiring object lock - synchronization blocks and methods- multiple threads may exist on same object but only one thread of that object can enter synchronized block/method at a time in java.



No comments:

Post a Comment