ArrayList (collection <? Extends E> c) thread safe?

Is streaming creating a new ArrayList instance ArrayList via the ArrayList(Collection<? extends E> sourceCollection) constructor ArrayList(Collection<? extends E> sourceCollection) without additional synchronization, assuming the sourceCollection synchronized? More specifically, can we rely in this case on the new list to contain exactly those elements that were in the collection when calling new ArrayList(sourceCollection) ? And can we rely on the new list to be in a consistent state?

I ask this question because I saw examples in concurrency books on how to restrict objects to local variables in a thread stack. In these examples, a reference to a shared object is passed to the method, and inside the method a copy of the object is stored in a local variable - all this without any synchronization. It is argued that thread safety can be achieved in this way. General example:

 public void someMethod(Collection<String> source) { List<String> localList = new ArrayList<>(source); ... } 
+5
source share
2 answers

Hint : as @ John Bollinger rightly mentioned, a specific implementation of ArrayList not covered by the language specification. So the following is true for Oracle java 8 implementation.


Yes, it is safe if source is a synchronized collection, because the ArrayList constructor in this case uses the t23> collection method, which also synchronizes and creates a new copy of the data:

 public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); // ... } 
+4
source

The answer to your specific question is the answer to the question - is the streaming collection safe?

The best way to try to understand how we get there, we can go to the source.

Starting with ArrayList

 public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } 

Diving in the documentation for Collection.toArray

 /** * Returns an array containing all of the elements in this collection. * If this collection makes any guarantees as to what order its elements * are returned by its iterator, this method must return the elements in * the same order. * * <p>The returned array will be "safe" in that no references to it are * maintained by this collection. (In other words, this method must * allocate a new array even if this collection is backed by an array). * The caller is thus free to modify the returned array. * * <p>This method acts as bridge between array-based and collection-based * APIs. * * @return an array containing all of the elements in this collection */ Object[] toArray(); 

Return to ArrayList.toArray (Assuming the source set environment type is ArrayList)

 /** * Returns an array containing all of the elements in this list * in proper sequence (from first to last element). * * <p>The returned array will be "safe" in that no references to it are * maintained by this list. (In other words, this method must allocate * a new array). The caller is thus free to modify the returned array. * * <p>This method acts as bridge between array-based and collection-based * APIs. * * @return an array containing all of the elements in this list in * proper sequence */ public Object[] toArray() { return Arrays.copyOf(elementData, size); } 

and finally on Array.copyOf

 /** * Copies the specified array, truncating or padding with nulls (if necessary) * so the copy has the specified length. For all indices that are * valid in both the original array and the copy, the two arrays will * contain identical values. For any indices that are valid in the * copy but not the original, the copy will contain <tt>null</tt>. * Such indices will exist if and only if the specified length * is greater than that of the original array. * The resulting array is of the class <tt>newType</tt>. * * @param <U> the class of the objects in the original array * @param <T> the class of the objects in the returned array * @param original the array to be copied * @param newLength the length of the copy to be returned * @param newType the class of the copy to be returned * @return a copy of the original array, truncated or padded with nulls * to obtain the specified length * @throws NegativeArraySizeException if <tt>newLength</tt> is negative * @throws NullPointerException if <tt>original</tt> is null * @throws ArrayStoreException if an element copied from * <tt>original</tt> is not of a runtime type that can be stored in * an array of class <tt>newType</tt> * @since 1.6 */ public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } 

System.arraycopy is a native method. A call to c.toArray at the top of the call stack uses System.arraycopy , which is a native method that is not documented as thread safe.

Moving back on the stack, the answer to your specific question - the answer to the question - is the source data stream safe?

If you are using an ArrayList as your source collection, you need to ensure thread safety in your code.

0
source

Source: https://habr.com/ru/post/1264210/


All Articles