简体   繁体   English

的ArrayList(收藏 <? extends E> c)线程安全吗?

[英]ArrayList(Collection<? extends E> c) thread safe?

Is it thread safe to create a new instance of ArrayList via constructor ArrayList(Collection<? extends E> sourceCollection) without any additional sychronization, supposing that sourceCollection is synchronized? 通过构造函数ArrayList(Collection<? extends E> sourceCollection)创建一个新的ArrayList实例,而没有任何额外的同步,假设sourceCollection是同步的,是否可以安全线程? More specifically, can we rely in that case on the new list to contain exactly the elements that were in the collection at the time new ArrayList(sourceCollection) was invoked? 更具体地说,我们可以在新列表中依赖于这种情况,以便在调用new ArrayList(sourceCollection)时准确包含集合中的元素吗? And can we rely on the new list to be in a consistent state? 我们可以依赖新列表处于一致状态吗?

I'm asking this question because I've seen examples in books on concurrency of how to confine objects to local variables on a thread's stack. 我问这个问题是因为我在书中看到了关于如何将对象限制在线程堆栈上的局部变量的并发性的书中的例子。 In these examples a method is passed a reference to a shared object, and inside the method a copy of the object is stored in a local variable -- all this without any synchronization. 在这些示例中,方法传递对共享对象的引用,并且在方法内部,对象的副本存储在本地变量中 - 所有这些都没有任何同步。 It is claimed that thread safety can be achieved in this way. 据称可以通过这种方式实现螺纹安全。 A general example would be: 一般的例子是:

public void someMethod(Collection<String> source) {
    List<String> localList = new ArrayList<>(source);
    ...
}

Hint : as @John Bollinger justly mentioned, particular ArrayList implementation is not covered by language specification. 提示 :正如@John Bollinger所提到的,特定的ArrayList实现不在语言规范中。 So written below is true for Oracle java 8 implementation. 所以下面的内容适用于Oracle java 8实现。


Yes, it is safe if source is synchronised collection, because ArrayList constructor in this case uses toArray() method of source collection, which is synchronised as well and produce new copy of data: 是的,如果source是同步集合则是安全的,因为在这种情况下, ArrayList构造函数使用源集合的toArray()方法,它同步并生成新的数据副本:

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

The answer to your specific question is the answer to the question - is the source collection thread safe? 您的具体问题的答案是问题的答案 - 源集合线程安全吗?

The best way to go about trying to understand how we get there, we can go to the source. 试图了解我们如何到达那里的最佳方式,我们可以去源头。

Starting with ArrayList 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 into the documentation for Collection.toArray 深入了解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();

Back to ArrayList.toArray (Assuming the source collections runtime type is an ArrayList) 返回ArrayList.toArray (假设源集合运行时类型是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 onto Array.copyOf 最后到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. System.arraycopy是一种本机方法。 The call to c.toArray at the top of its invocation stack uses System.arraycopy which is a native method which isn't documented to be thread safe. 在其调用堆栈顶部对c.toArray的调用使用System.arraycopy ,这是一种本机方法,未记录为线程安全。

Moving back down the stack, the answer to your specific question is the answer to the question - is the source collection thread safe? 回到堆栈,你的具体问题的答案是问题的答案 - 源集合线程安全吗?

If you are using an ArrayList as the source collection, you will need to ensure thread safety in your code. 如果您使用ArrayList作为源集合,则需要确保代码中的线程安全。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 的ArrayList(收藏 <? extends E> C) - ArrayList(Collection<? extends E> c) ArrayList上的MergeSort仅与ArrayList(Collection <? extends E> c)不是ArrayList(int initialCapacity)吗? - MergeSort on ArrayList only work with ArrayList(Collection<? extends E> c) not ArrayList(int initialCapacity)? 当使用 ArrayList(Collection<? extends E> c) 对于复制构造函数,我收到两个错误 - When using ArrayList(Collection<? extends E> c) for a copy constructor I get two errors 如何重写Java的ArrayList的addAll(Collection <? extends E> c)Scala中的方法? 天真的方法不能编译 - How to override Java's ArrayList's addAll(Collection<? extends E> c) method in Scala? Naive approach does not compile 这到底是什么意思收藏<? extends E> C - What exactly does this mean Collection<? extends E> c 复制`ArrayList 是否安全<E> `以这种方式? - Is it safe to copy `ArrayList<E>` in this manner? 存储在线程安全的集合中的对象是否安全? - Are objects stored in thread safe collection thread safe? `ArrayList::get` 线程安全吗? - Is `ArrayList::get` thread-safe? HashTable中的ArrayList是线程安全的 - ArrayList inside HashTable is thread safe Java扩展RuntimeException字段值是线程安全的吗? - Java Extends RuntimeException filed value is thread safe?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM