Reputation: 13
My professor was discussing issues that can arise when multiple threads concurrently access the same data field of an object with the following code
@Override
public void run() {
// main for a thread
for (int i = 0; i < 1_000_000; i++) {
list.add(i);
}
}
the code threw an IndexOutOfBoundsException: Index 13 out of bounds for length 10
and the explanation he gave is that the 2 threads hit the max capacity and then thread1
would add enough to trigger a second resize which then got overridden by thread2
's first resize making it smaller than thread1
's insertion point. That would make sense for most IndexOutOfBoundsExceptions
, but isn't the ArrayList
's default size set to 10, so in this case thread2
can't resize down to 10 and some other issue caused the IndexOutOfBoundsException
?
How did the size get downsized to 10?
Upvotes: 1
Views: 70
Reputation: 96424
If the list is created like this:
List list = new ArrayList(0);
then that would set the initial capacity to 0, not 10, and that would provide opportunity for different threads to force an allocation and cause the exception as shown.
Since you don't provide code all we can do is speculate. Questions like this should include a minimal reproducible example that viewers can use to recreate the issue, or you will get guesses. It does seem unlikely that the list would get downsized. It seems less unlikely that the description is inaccurate or missing some important detail.
The point is that a thread can act in between the memory allocation and the adding of a new element being done by another thread, because the ArrayList does not protect against concurrent modifications.
ArrayList was designed explicitly not to be threadsafe, if you check the API documentation you will find this warning:
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.)
It is very common that modifying a data structure is implemented in multiple steps, and another thread can get in between any two of these and cause trouble. This is why you should take care to use threadsafe data structures, and be very careful about creating your own data structures to use in a concurrent environment.
Upvotes: 4