How can I achieve the safe read/write concurrency on an ArrayList?
It's hard to figure out what is actually happening to the list. Items are being added to the end of the while readers are consuming from the front but I can't tell if multiple readers read a single item or does every reader consume every element?
But regardless, I would consider switching to using a BlockingQueue
like an ArrayBlockingQueue
. ArrayList
is not at all built for your use case. I would have a BlockingQueue
for the work and then another BlockingQueue
for the results. Again, this assumes that entries in your list are not consumed by multiple threads.
One of the main issues here is that synchronization performances two functions: mutex protection and memory synchronization. The writers have to lock so they don't collide but the readers need to lock to be able to see the writers' updates to the list.
In terms of the blocking specifics, some of your requirements are not possible because of the race conditions involved with dynamically extending the list.
I am making an assumption here that merely writing to the end of ArrayList is thread safe for the reader of the array's start
This is true unless the write to the end of the list causes the list to be reallocated. However, again, you need to synchronize on the list to see any of the updates made to the list by the writers. Even if your ArrayList
is volatile
the fields inside of the list are not.
I am making an assumption here that reallocating the memory of ArrayList is NOT thread safe for the reader of the array's start...
No it is not. No part of the ArrayList
is thread safe when it comes to the array of data. I'd recommend looking at the source if there is any question. The following method is called from add(...)
and any other method that changes the size of the list.
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
}