开发者

Concurrently read and set on Java ArrayList (or something similar)

In Java, if multiple thread read values in a java.util.ArrayList and one of them may set an entry by calling ArrayList.set(index, newVal) is that going to work? 开发者_Python百科(I'll explain what I mean by 'work')

Assume that the size of the array list does not change (it's predefined and filled with null for instance). Also assume that only one designated thread will call the set method.

I consider it to work fine as long as

  1. it does not throw any kind of exceptions,
  2. the updated entry will be seen by read threads eventually.


If you're only setting values not changing the length then this is probably okay for your use. From the ArrayList javadoc.

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. (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.)

If you were making structural modifications, or multiple threads were writing to the ArrayList then you would want to use Collections.synchronizedList to get a thread safe list.


Point 1) is given using your normal array list, if you are doing no structural modifications.

Point 2) may be given in practice too, but there are no guarantees about that in the Java memory model. So, you'll have to ensure this someway externally. Either use some volatile variable to guarantee an happens-before relationship, or do the same with synchronizing. There is also a lazySet() method on AtomicReference (and the other AtomicXXX classes), which may help here, but I'm not sure I understand it right.


I think you can do something like this

List list = Collections.synchronizedList(new ArrayList());
      ...
  synchronized(list) {
      Iterator i = list.iterator(); // Must be in synchronized block
      while (i.hasNext())
          foo(i.next());
  }


1) it does not throw any kind of exceptions, 2) the updated entry will be seen by read threads eventually.

Very generally speaking, if the array is fixed length (ensured) and there are no add's or removals then the answer is, yes it will work without exceptions. A fixed length array list is no different then array of length N. All the set does on the inner workings is similar (but not identical) to:

Object array [] = new Object[N];

public void set(int index, Object value){
  array[index] =value;
}

This of course is an implementation detail and is guaranteed from release to release. Memory visibility and ordering is not ensured but if that isnt a concern for you then a simple set shouldn't cause an unexpected errors (As of Java 1.6_24)


If consistency isn't necessery, you can read and set concurrently without locking. Every time you want to modify the array, bulid a new array, modify it and copy the reference to the new array, leave the old one to JVM.

Array tempArr = new ArrayList<Object>(yourOldArr);
// modify the tempArray without changing the size
tempArr[0] = element;
yourOldArr = tempArr; // atomic operation

If you wanna modiy the tempArr's length, you can return a copy of your old array, every time you read it.


Writes to and reads of references are always atomic, regardless of whether they are implemented as 32 or 64 bit values so you are safe there.

However, it isn't GUARANTEED to work because because there isn't a guarantee that the ArrayList implementation might not do some housekeeping on get / set even if the list length doesn't change. This housekeeping might not be thread safe. Imagine for instance you create an array list and resize the capacity never to change it again. Unknown to you the array list defers work only moving over a few elements from the old backing array to the new backing array each get/put so that the resize runs in constant time. A set might place a value 0xbeefbabe into the new backing array while a concurrent get is transferring a value 0xahhhhe11 from the old backing array overwriting the new value.

Also get might "never" see the change if a smart enough optimizer decides to use aggressive inlines and the get code is optimized away.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜