69
List<String> list = Collections.synchronizedList(new ArrayList<String>());
synchronized (list) {
    list.add("message");
}

Is the block "synchronized (list){} " really need here ?

Stephan
  • 4,395
  • 3
  • 26
  • 49
romsky
  • 864
  • 1
  • 8
  • 11

6 Answers6

100

You don't need to synchronize as you put in your example. HOWEVER, very important, you need to synchronize around the list when you iterate it (as noted in the Javadoc):

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());   
}
Tim
  • 41,901
  • 18
  • 127
  • 145
Sam Goldberg
  • 6,711
  • 8
  • 52
  • 85
  • 17
    Link to the above statement: [docs](http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#synchronizedList(java.util.List)) – Martin Andersson Feb 13 '13 at 09:28
  • 2
    A common use case with a synchronised collection like this is to add to the list in multiple threads, but to iterate it only at the end when all tasks have complete. In this case, I don't see any reason to synchronise around the iteration, since it's being done from a single thread. – Desty Aug 06 '13 at 12:30
  • 5
    As long as you know the list is not being updated while you're iterating, you don't need to synchronize it. I don't know if I would characterize that use case as "common", though. (I've seen ConcurrentModificationException quite a number of times.) In the use case you mention, what's preventing a thread from adding to the list again while the other thread is iterating? And how does the iterating thread "know" when the other threads are done updating the list? – Sam Goldberg Aug 06 '13 at 13:50
  • Similarly for Collections.synchornizedMap, need to use synchronized keyword for iteration or manipulation of Map – pramodc84 Nov 28 '14 at 11:04
  • If the list is not synchronized, won't there anyways be a concurrent modification exception? – user9791370 Jun 24 '19 at 14:13
29

It depends on the exact contents of the synchronized block:

  1. If the block performs a single, atomic operation on the list (as in your example), the synchronized is superfluous.

  2. If the block performs multiple operations on the list -- and needs to maintain the lock for the duration of the compound operation -- then the synchronized is not superfluous. One common example of this is iterating over the list.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
22

The underlying code for Collections.synchronizedList add method is:

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

So in your example it is not needed to add synchronisation.

assylias
  • 321,522
  • 82
  • 660
  • 783
17

Also Important to note that any methods that use Iterators for example Collections.sort() will also need to be encapsulated inside a synchronized block.

jpegjpg
  • 175
  • 1
  • 5
  • from Java 8, the sort method has been added to the List interface and this method already synchronizes on the mutex. https://docs.oracle.com/javase/8/docs/api/java/util/List.html#sort-java.util.Comparator- – Bogdan T. Dec 09 '17 at 16:38
7

Read this Oracle Doc

It says "It is imperative that the user manually synchronize on the returned list when iterating over it"

Community
  • 1
  • 1
snan
  • 71
  • 1
  • 1
1

Like what has been mentioned by others, the synchronized collections are thread-safe, but the compound actions to these collections are not guaranteed to be thread-safe by default.

According to JCIP, the common compound actions can be

  • iteration
  • navigation
  • put-if-absent
  • check-then-act

The OP's synchronized code block isn't a compound action, so no difference whether add it or not.

Let's take the example from JCIP and modify it a little to clarify why it's necessary to guard the compound actions with lock.

There are two methods that operate on same collection list that wrapped by Collections.synchronizedList

public Object getLast(List<String> list){
    int lastIndex = list.size() - 1;
    return list.get(lastIndex);
}

public void deleteLast(List<String> list){
    int lastIndex = list.size() - 1;
    list.remove(lastIndex);
}

If methods getLast and deleteLast are called at the same time by two different threads, below interleaves may happen and getLast will throw ArrayIndexOutOfBoundsException. Assume current lastIndex is 10.

Thread A (deleteLast) --> remove
Thread B (getLast) --------------------> get

The Thread A remove the element before the get operation in Thread B. Thus, the Thread B still use 10 as the lastIndex to call list.get method, it will lead to concurrent problem.

Eugene
  • 10,627
  • 5
  • 49
  • 67