4

I am aware that ArrayList is not thread safe, but I'm unsure about the exact implications of this.

In the case of ThreadA and ThreadB both using an ArrayList, which of these situations will cause issues and necessitate synchronization?

  1. Both threads simultaneously reading the same index
  2. ThreadA replacing an element which ThreadB is attempting to access simultaneously, assuming that you don't care whether or not ThreadB gets the old or the new element.
7
  • By "accessing the same index" do you mean reading, writing, or both? Commented Mar 10, 2014 at 13:27
  • Thread safety usually implies write operations, and change of states. If both thread just use the list for reading, you are fine. Commented Mar 10, 2014 at 13:28
  • 1
    "You don't care whether ThreadB gets the old or new element." What if ThreadB gets a little bit of both? Would that be problematic? Commented Mar 10, 2014 at 13:29
  • @BilltheLizard there, edited it for clarity Commented Mar 10, 2014 at 13:32
  • @Heuster yes, that would be problematic! Commented Mar 10, 2014 at 13:36

3 Answers 3

3

Both threads simultaneously reading the same index

It is okay for multiple threads to be reading from common ArrayList if the list was constructed by the thread that forked the ThreadA and ThreadB and the list is fully constructed and loaded before the threads were forked.

The reason for this is that there is a happens-before guarantee with a thread and the memory of the thread that forked it. If, for example, ThreadC builds the ArrayList but after ThreadA and ThreadB are forked, then there is no guarantee that A and B will fully see the ArrayList -- if at all.

If this is not the case then you will need to synchronize the list. See below.

ThreadA changing an element which ThreadB is attempting to access simultaneously, assuming that you don't care whether or not ThreadB gets the old or the new element.

Once you talk about modifications to the list in a concurrent setting, then you must synchronize on that list otherwise there is no guarantee that the modifications will be published and there are chances that the list could be partially published which could cause data exceptions. As @Marko puts it, its internal state may be inconsistent.

You can either use a CopyOnWriteArrayList which is designed for few updates and many reads, use Collections.synchronizedList(...) to make your list be protected, you can access the list always in a synchronized block (for all writes and reads), or you can switch to using a concurrent collection such as ConcurrentSkipList or something.

ThreadA changing an element which ThreadB is attempting to access simultaneously

This is somewhat ambiguous. If you are talking about, for example, storing objects in the list and then changing the objects that happen to be stored in the list then you are not going to have a synchronization problem on the list but you will have a synchronization problem with the object. If the list's data is not changing then it will be fine. However, if you need to protect the object then either a list of AtomicReference<YourObject>, volatile fields in the object, or other synchronization is required to make sure the changes are published between the threads.

Sign up to request clarification or add additional context in comments.

3 Comments

Why does it matter whether the list was constructed and fully formed before forking of the threads?
I've added details about this to my answer @s1ice. It's about the happens-before guarantee with one thread forking another.
nice to know! Thanks for pointing out the ambiguity in my #2, I cleared it up.
2

In your question I see an emphasis on simultaneous access.

The issues with concurrent access have very little to do with simultaneity. To put it more strongly, even if you ensure no simultaneous access happens, you are still a long way from a thread-safe program.

Answers to your specific points:

1) Both threads simultaneously reading the same index

As long as your threads only read and never write, you are safe regardless of simultaneity.

2) ThreadA changing an element which ThreadB is attempting to access simultaneously, assuming that you don't care whether or not ThreadB gets the old or the new element.

Whether or not writing happens at the same time as reading, you are in trouble. You are not just in danger of seeing stale values; you can see a completely broken List object (its internal state is inconsistent).

If any thread changes the list, you need synchronization.

For more information I strongly advise getting acquainted with the Java Memory Model, preferrably from the corresponding section in the Java Language Specification.

2 Comments

"As long as your threads only read and never write, you are safe regardless of simultaneity." - provide the list was safely published in the first place and hasn't been changed by a 3rd thread since.
There's no "3rd thread" in the question :) The sentence that actually needs qualification is this one: "If any thread changes the list, you need synchronization." because it doesn't apply if the thread which changes the list does it before the reading threads come to life.
0

If you initialize the list prior to publishing it, there's no problem with having multiple threads reading from the list.

As soon as you are reading and writing to the list concurrently, you need to synchronize access to it.

5 Comments

So do you disagree with 2. in the answer Andres posted?
Yes, 2. is bad. If you don't care about ThreadB seeing an old copy of the list you might consider CopyOnWriteArrayList
+1 To be more specific. If you initialize the list in the same thread that then forks the two threads that are doing the reading then you are fine.
But suppose ThreadA is creating new object and then writes it at given index. ThradB then will read this index (at any time), also ThreadB will not modify List. I suppose it is possible to make it safe. I think keeping references as AtomicReference-s would be recomended.
I'm not sure I fully understand you. If you have mutable objects inside your list, you can mutate them without affecting the thread safety of the list (you may hit other concurrency issues though). You can not add() remove() or set() items in an ArrayList concurrently.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.