3

For one thing, according to the Javadoc below:

If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.)

synchronization is not necessary.

For another, setting the value of an element is an atomic action so it cannot be interleaved. However, memory consistency errors are still possible.

So which is right?

Edit: Maybe I haven't expressed myself clearly. Actually, I just wanna know whether the Javadoc is wrong or at least misleading. By the way, I said setting the value of an element is an atomic action, but this is obviously wrong.

jddxf
  • 1,850
  • 3
  • 12
  • 19
  • @TheLostMind: but an `ArrayList` is a generics list, that means it can only store `Objects`, no primitive types: you need to use `Long` instead of `long` thus pointers... – Willem Van Onsem Sep 15 '15 at 11:03
  • where does it say "synchronization is not necessary."? elements of an array are not `volatile` and you need synchronization if you want to ensure visibility. It won't blow up like when you do structural change though. – zapl Sep 17 '15 at 01:59
  • @zapl: as noted by biziclop, the Javadoc doesn't say it explicitly but hints at it. – jddxf Sep 17 '15 at 03:48
  • @jddxf ah yes, I see. Btw ArrayList set operation (just the actual array modification) is atomic because it stores object references http://stackoverflow.com/questions/2576513/is-writing-a-reference-atomic-on-64bit-vms – zapl Sep 17 '15 at 16:32
  • @zapl:that's why I said it's atomic before.but set operation does something else besides writing a reference. – jddxf Sep 18 '15 at 00:46
  • 1
    @jddxf it checks if you are within bounds and it reads the old value before it sets a new one. Those three steps don't happen atomically but if you don't make structural changes and you don't care about the return value, you got the guarante that your `set()` is atomic [based on the current implementation - relying on that to not change or to be the same in alternative java implementations is another question]. I doubt that there is much use for this practice though since that's a very weak guarantee for a concurrent system. – zapl Sep 18 '15 at 08:57

3 Answers3

2

I guess what you want is a guarantee that iterators won't be invalidated if List.set(int, E) is called during the iterator's lifetime. I think this is something that varies from one List implementation to another so if the documentation doesn't explicitly say that List.set(int, E) is thread-safe, assume that it isn't. In practice you might find that an array implementation will not invalidate the iterator but you don't want to rely on any undocumented behaviour in a third-party library - if you want to enforce some condition you should do it in your own code.

An example of a class that does provide a guarantee that List.set(int, E) doesn't invalidate iterators, however: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArrayList.html

Injektilo
  • 581
  • 3
  • 14
1

I don't think it's a good idea to make assumptions on how setting a value in ArrayList is implemented. The important thing is that if you are given no consistency guarantees in the Javadoc, you should always synchronize externally when multiple threads are using the same ArrayList.

Or, depending on the use case, choose a different structure altogether, one that was designed for concurrency, like CopyOnWriteArrayList. (Though always make sure you choose the right one, as they don't perform equally well under all circumstances.)

In this case the Javadoc doesn't explicitly say you can omit sychronization if you only use set(), merely hints at it. And the hint is wrong because as you say, memory consistency isn't guaranteed at all, you can easily end up reading stale values, or multiple set() calls can be reordered.

biziclop
  • 48,926
  • 12
  • 77
  • 104
0

if you need synchronize an ArrayList seems like you made a bad decision about which component use. You should use Vector which is syncronized

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
paul
  • 12,873
  • 23
  • 91
  • 153
  • Although it is advisable to use a Vector, I don't know if this answers the question... – Willem Van Onsem Sep 15 '15 at 11:10
  • 3
    You don't want to use Vector. It's a fundamentally bad design and only there for backwards compatibility. see: http://stackoverflow.com/a/1386288/790762 – Injektilo Sep 15 '15 at 11:45