Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - Thread safety of ArrayList constructors

I am looking at this piece of code. This constructor delegates to the native method "System.arraycopy"

Is it Thread safe? And by that I mean can it ever throw a ConcurrentModificationException?

public Collection<Object> getConnections(Collection<Object> someCollection) {
    return new ArrayList<Object>(someCollection);
}

Does it make any difference if the collection being copied is ThreadSafe eg a CopyOnWriteArrayList?

public Collection<Object> getConnections(CopyOnWriteArrayList<Object> someCollection) {
    return new ArrayList<Object>(someCollection);
}

Edit: I am aware that ThreadSafe != ConcurrentModificationException. I am trying to take a snapshot of data at a point in time. Therefore if another Thread writes to someCollection midway thru the copy I dont care if the result has the new object or not. I just dont want it to throw a ConcurrentModificationException or worse

like image 913
andy boot Avatar asked Apr 21 '10 09:04

andy boot


2 Answers

This constructor delegates to the native method "System.arraycopy"

Actually, it calls toArray() on someCollection. That will eventually call System.arraycopy if someCollection is an ArrayList. For other collection types the array will be created in other ways.

Is it Thread safe?

No.

And by that I mean can it ever throw a ConcurrentModificationException?

If it is an ArrayList it won't throw ConcurrentModificationException ... but that does not make it thread-safe!!

I am trying to take a snapshot of data at a point in time.

You won't (always) get a consistent snapshot.

For example, if a different thread calls set(obj, pos) on someCollection while your thread is calling this constructor, then the contents of your newly created ArrayList are unpredictable.

In the Java 11 version, the ArrayList(Collection) constructor calls toArray() on the argument collection. The resulting ArrayList will be a consistent snapshot of the collection if and only if the toArray call is guaranteed to give a consistent snapshot. This is true for some collection classes (for example CopyOnWriteList) but not in general.

like image 153
Stephen C Avatar answered Oct 14 '22 22:10

Stephen C


Your question is whether you can safely get a snapshot of a collection that might be undergoing concurrent modification by another thread using new ArrayList<Foo>(thatCollection). The answer is: as long as thatCollection itself is thread-safe, yes. So if it's a CopyOnWriteArrayList, synchronizedList or Vector, If it's not thread-safe, for example if it's another ArrayList, you're not fine. (What will happen could be worse than a ConcurrentModificationException.)

The reason is that the ArrayList constructor makes only a single atomic call to the other collection -- to its toArray method. So it essentially enjoys whatever thread-safety guarantees that method itself has. It was not always implemented like this, but is now for just this reason. We do the same thing in Guava with ImmutableList.copyOf.

like image 44
Kevin Bourrillion Avatar answered Oct 14 '22 23:10

Kevin Bourrillion