views:

284

answers:

4

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

+3  A: 

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!!

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.

Stephen C
+1  A: 

ConcurrentModificationException is not the only sign of something being not thread safe. If for example in method #1 someCollection is also an ArrayList, you will never have a ConcurrentModificationException (see the code). However, data integrity is at risk - if the source ArrayList is altered during its copying, only some of the changes may be reflect in the copy (and not necessarily the oldest changes!).

In other words, atomicity is not guaranteed (unless the source is specifically designed for it, such as with CopyOnWriteArrayList).

EDIT: actually, assumning that you don't synchronize your threads properly, copying an array with one thread while another thread updates references in it is problematic in the Java Memory Model, and theoretically can result in unpredictable behavior.

Eyal Schneider
That is not a theoretical problem: unpredictable behavior *will* occur. The only point of uncertainty is *how often* it will occur.
Stephen C
@Stephen: you are right, but reproducing out-of-order-write bugs is extremely difficult. I found only one example in the following article: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Eyal Schneider
Difficult to reproduce != theoretical. Also, few examples described in webpages != theoretical. :-)
Stephen C
+4  A: 

Thread safe and ConcurrentModificationException are different concepts. A thread safe object is one where multiple threads can call its methods at the same time, and the data held within the object is guaranteed not to become corrupted (example: http://thejavacodemonkey.blogspot.com/2007/08/making-your-java-class-thread-safe.html). A ConcurrentModificationException occurs when, for example, you are in the middle of iterating through a collection, and the collection changes. The change might come from a different thread, or the same thread.

In your constructor, if another thread changes the someCollection while your constructor is copying it, it could result either in undefined behaviour (i.e. data corruption in your new collection, because the collections are not thread safe), or a ConcurrentModificationException (if the collection does detect the concurrent modification, but this is not guaranteed, because it is not thread safe... :-)

If your constructor is going to take a Collection<Object>, you would need to ensure that other threads do not modify the collection until after your constructor returns.

On the other hand, a CopyOnWriteArrayList is thread safe and guarantees not to throw ConcurrentModificationException, so you should be safe doing it this way, without writing extra synchronization code.

Joe Daley
+1  A: 

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.

Kevin Bourrillion