Languages
[Edit]
EN

Java - create thread safe ArrayList (Collections.synchronizedList)

7 points
Created by:
Brett4
435

In this article, we would like to show you how to create thread safe ArrayList in java.

Quick solution:

List<String> syncList = Collections.synchronizedList(new ArrayList<>());

 

Full example with imports:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Example {

    public static void main(String[] args) {

        List<String> results = Collections.synchronizedList(new ArrayList<>());

        // now we can safely use this list between different threads
        // as all methods of this list are synchronized

        results.add("A");
        results.addAll(Arrays.asList("B", "C"));

    }
}

 

Iterating over Collections.synchronizedList

When iterating the iterator must be synched by programmer.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class Example {

    public static void main(String[] args) {

        List<String> results = Collections.synchronizedList(new ArrayList<>());

        // now we can safely use this list between different threads
        // as all methods of this list are synchronized

        results.add("A");
        results.addAll(Arrays.asList("B", "C"));
        
        synchronized (results) {
            Iterator<String> iterator = results.iterator(); // Must be in synchronized block
            while (iterator.hasNext()) {
                System.out.println(iterator.next());
                
                // other operations
                
            }
        }
    }
}

Let's take a look at java docs:

// It is imperative that the user manually synchronize on the returned list when iterating over it:
List list = Collections.synchronizedList(new ArrayList());
synchronized (list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());
}

We can take a look at implementation of SynchronizedList:

public ListIterator<E> listIterator() {
	return list.listIterator(); // Must be manually synched by user
}

public ListIterator<E> listIterator(int index) {
	return list.listIterator(index); // Must be manually synched by user
}

Explanation

When we enter Collections.synchronizedList(new ArrayList<>()) method, we will see that all methods of list are wrapped by synchronized.

// entire synchronization is on below lock / mutex / mutual exclusion:
final Object mutex;     // Object on which to synchronize

We can read more about lock / mutex here:

Java Collections synchronizedList implementation (java 11 corretto):

package java.util;

// ...

public class Collections {

	// ...

    static class SynchronizedCollection<E> implements Collection<E>, Serializable {
        private static final long serialVersionUID = 3053995032091335093L;

        final Collection<E> c;  // Backing Collection
        final Object mutex;     // Object on which to synchronize

	// ...

    }

	// ...

	public static <T> List<T> synchronizedList(List<T> list) {
			return (list instanceof RandomAccess ?
					new SynchronizedRandomAccessList<>(list) :
					new SynchronizedList<>(list));
	}

	static <T> List<T> synchronizedList(List<T> list, Object mutex) {
		return (list instanceof RandomAccess ?
				new SynchronizedRandomAccessList<>(list, mutex) :
				new SynchronizedList<>(list, mutex));
	}

	/**
	 * @serial include
	 */
	static class SynchronizedList<E>
		extends SynchronizedCollection<E>
		implements List<E> {
		private static final long serialVersionUID = -7754090372962971524L;

		final List<E> list;

		SynchronizedList(List<E> list) {
			super(list);
			this.list = list;
		}
		SynchronizedList(List<E> list, Object mutex) {
			super(list, mutex);
			this.list = list;
		}

		public boolean equals(Object o) {
			if (this == o)
				return true;
			synchronized (mutex) {return list.equals(o);}
		}
		public int hashCode() {
			synchronized (mutex) {return list.hashCode();}
		}

		public E get(int index) {
			synchronized (mutex) {return list.get(index);}
		}
		public E set(int index, E element) {
			synchronized (mutex) {return list.set(index, element);}
		}
		public void add(int index, E element) {
			synchronized (mutex) {list.add(index, element);}
		}
		public E remove(int index) {
			synchronized (mutex) {return list.remove(index);}
		}

		public int indexOf(Object o) {
			synchronized (mutex) {return list.indexOf(o);}
		}
		public int lastIndexOf(Object o) {
			synchronized (mutex) {return list.lastIndexOf(o);}
		}

		public boolean addAll(int index, Collection<? extends E> c) {
			synchronized (mutex) {return list.addAll(index, c);}
		}

		public ListIterator<E> listIterator() {
			return list.listIterator(); // Must be manually synched by user
		}

		public ListIterator<E> listIterator(int index) {
			return list.listIterator(index); // Must be manually synched by user
		}

		public List<E> subList(int fromIndex, int toIndex) {
			synchronized (mutex) {
				return new SynchronizedList<>(list.subList(fromIndex, toIndex),
											mutex);
			}
		}

		@Override
		public void replaceAll(UnaryOperator<E> operator) {
			synchronized (mutex) {list.replaceAll(operator);}
		}
		@Override
		public void sort(Comparator<? super E> c) {
			synchronized (mutex) {list.sort(c);}
		}

		/**
		 * SynchronizedRandomAccessList instances are serialized as
		 * SynchronizedList instances to allow them to be deserialized
		 * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList).
		 * This method inverts the transformation.  As a beneficial
		 * side-effect, it also grafts the RandomAccess marker onto
		 * SynchronizedList instances that were serialized in pre-1.4 JREs.
		 *
		 * Note: Unfortunately, SynchronizedRandomAccessList instances
		 * serialized in 1.4.1 and deserialized in 1.4 will become
		 * SynchronizedList instances, as this method was missing in 1.4.
		 */
		private Object readResolve() {
			return (list instanceof RandomAccess
					? new SynchronizedRandomAccessList<>(list)
					: this);
		}
	}

	/**
	 * @serial include
	 */
	static class SynchronizedRandomAccessList<E>
		extends SynchronizedList<E>
		implements RandomAccess {

		SynchronizedRandomAccessList(List<E> list) {
			super(list);
		}

		SynchronizedRandomAccessList(List<E> list, Object mutex) {
			super(list, mutex);
		}

		public List<E> subList(int fromIndex, int toIndex) {
			synchronized (mutex) {
				return new SynchronizedRandomAccessList<>(
					list.subList(fromIndex, toIndex), mutex);
			}
		}

		private static final long serialVersionUID = 1530674583602358482L;

		/**
		 * Allows instances to be deserialized in pre-1.4 JREs (which do
		 * not have SynchronizedRandomAccessList).  SynchronizedList has
		 * a readResolve method that inverts this transformation upon
		 * deserialization.
		 */
		private Object writeReplace() {
			return new SynchronizedList<>(list);
		}
	}

	// ...
	
}

 

Donate to Dirask
Our content is created by volunteers - like Wikipedia. If you think, the things we do are good, donate us. Thanks!
Join to our subscribers to be up to date with content, news and offers.

Java concurrency

Native Advertising
🚀
Get your tech brand or product in front of software developers.
For more information Contact us
Dirask - we help you to
solve coding problems.
Ask question.

❤️💻 🙂

Join