5

Consider a for-loop over a function that takes an ArrayList reference and adds an object to that ArrayList. I would now like to execute each function call in parallel.

Is the ArrayList.add() method thread safe if I don't care about the sequence the objects are added and no function reads or manipulates any ArrayList elements? So I only want to make sure that at the end of the parallel call all objects are added to the list.

madison54
  • 743
  • 2
  • 8
  • 19
  • possible dup http://stackoverflow.com/questions/2715983/concurrent-threads-adding-to-arraylist-at-same-time-what-happens – santosh-patil Dec 12 '14 at 11:12
  • try `Collections.synchronizedList(new ArrayList())` – rzysia Dec 12 '14 at 11:13
  • Are you not searching for a bag then? It can contain multiples, but order is irrelevant. I don't think Java provides a standard implementation, but it might help you in future searches. – skiwi Dec 12 '14 at 11:25
  • What OP actually needs is each thread accumulating its contribution in isolation, then merging the results from all threads. In other words, he needs `Stream.parallel()`. – Marko Topolnik Dec 12 '14 at 11:34
  • 1
    Right there in [the documentation](http://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html): "**Note that this implementation is not synchronized.** If multiple threads access an `ArrayList` instance concurrently, and at least one of the threads modifies the list structurally, it *must* be synchronized externally." **Not** my emphasis, the boldface and italics are actually in the docs. Docs are your first stop for information. – T.J. Crowder Dec 12 '14 at 11:45

6 Answers6

9

No, it's not thread-safe. Wrap your list using Collections.synchronizedList(), or use explicit synchronization when accessing the list.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • I would like to avoid the overhead of synchronization, as I'm not reading form the ArrayList...what happens if two threads want to concurrently add to an ArrayList? – madison54 Dec 12 '14 at 11:15
  • 4
    Anything could happen: it might work well, or elements could be lost, or you could get an exception, or the list could be in an incoherent state. Make your program correct then see if it's fast enough. If it is not, and if you prove that the synchronized access to the list is the problem (which is unlikely), then and only then think about how you could optimize the code. – JB Nizet Dec 12 '14 at 11:17
  • 1
    If OP ever concludes that, he'll find that no shared-state model can improve his performance. – Marko Topolnik Dec 12 '14 at 11:31
  • Just a note if someone comes looking for addAll(), no it is not thread safe either. – Akki Jun 03 '21 at 08:12
7

ArrayList.add() is not thread-safe. Even if you're not reading the list from other threads, you shouldn't rely on this logical assumption. Here's the definition of ArrayList.add():

public boolean add(E e) {
    ensureCapacity(size + 1);
    elementData[size++] = e;
    return true;
}

As an example of a problem that could arise without synchronization, the size attribute may be inconsistent after adding all elements. If you later try to get the number of elements, the result may not be correct.

M A
  • 71,713
  • 13
  • 134
  • 174
  • This actually underestimates the full potential for problems without synchronization. Even if the code appeared to be atomic, it would still be broken without synchronization. – Marko Topolnik Dec 12 '14 at 11:32
  • @MarkoTopolnik Indeed it is just a simple example. – M A Dec 12 '14 at 11:36
1

For that you can use CopyOnWriteArrayListsince ArrayList is not thread safe.

CopyOnWriteArrayList

EDIT: I'm just gonna quote Oracle to show you that this is what you need:

A thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array. This is ordinarily too costly, but may be more efficient than alternatives when traversal operations vastly outnumber mutations, and is useful when you cannot or don't want to synchronize traversals, yet need to preclude interference among concurrent threads.

Lucas
  • 3,181
  • 4
  • 26
  • 45
0

No, the add method uses a number of class level properties which have no thread safe control. Calling add() concurrently in multiple threads would be highly likely to cause problems.

BarrySW19
  • 3,759
  • 12
  • 26
0

No it is not thread safe.You have two options:

  1. Either use a different collection: CopyOnWriteArrayList
  2. Use explicit synchronization while making modifications to the array list in a multithreaded environment.
abhati
  • 309
  • 1
  • 6
0

It is not thread-safe. In the absence of synchronization, threads can trample on each other's modification of the list, or might not even see each other's changes to it. Either way, it will be corrupted.

You should get the code working first with Collections.synchronizedList or a synchronized statement around the add call.

If you find that the synchronization on every operation has too much overhead, the next alternative is to give each thread its own private ArrayList, and then periodically, or at the end, dump the contents of the private ArrayLists into the main ArrayList.

Boann
  • 48,794
  • 16
  • 117
  • 146