Java ArrayList(集合<;?扩展E>;c)线程安全?

Java ArrayList(集合<;?扩展E>;c)线程安全?,java,multithreading,arraylist,thread-safety,Java,Multithreading,Arraylist,Thread Safety,通过构造函数ArrayList(CollectionHint)创建ArrayList的新实例是否线程安全:正如@John Bollinger刚刚提到的,特定的ArrayList实现不在语言规范的范围内。下面所写的内容适用于Oracle java 8实现 是的,如果source是同步收集,则是安全的,因为在这种情况下ArrayList构造函数使用toArray()源收集方法,该方法也同步并生成数据的新副本: public ArrayList(Collection<? extends E&g

通过构造函数
ArrayList(CollectionHint)创建
ArrayList
的新实例是否线程安全:正如@John Bollinger刚刚提到的,特定的
ArrayList
实现不在语言规范的范围内。下面所写的内容适用于Oracle java 8实现


是的,如果
source
是同步收集,则是安全的,因为在这种情况下
ArrayList
构造函数使用
toArray()
源收集方法,该方法也同步并生成数据的新副本:

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

public ArrayList(Collection特定问题的答案就是问题的答案-源集合线程安全吗

要想了解我们是如何到达那里的,最好的办法就是找到源头


public ArrayList(CollectionIt仅当源是安全的(例如,不可变、同步或并发的)时才是安全的。你的意思是即使
sourceCollection
未同步?不,我的意思是已同步。如果传入一个集合源,你必须假设读取它并迭代它是安全的。否则…你能用它做什么?确保至少在方法调用中,集合具有稳定的e、 一致的视图。那么您就不需要方法本地副本。只是线程安全的定义之一以及Java并发中实际使用的定义之一是,如果一个类可以在没有类的客户端采取任何额外预防措施的情况下使用,以确保该类在多线程环境中的正确行为,那么它就是线程安全的从某种意义上说,但是所讨论的
ArrayList
构造函数没有被记录为那样的行为,并且其记录的行为与线程不安全的替代实现是一致的。从这个意义上说,不,建议的操作不是线程安全的。从这个意义上说,我们可以谈论非常广泛的事情。但是通常我会同意你的观点。@JohnBollinger在我的回答中添加了你的提示只是为了澄清:如果源集合由同步或锁保护,那么它是安全的,但是如果集合是由或创建的,则不能保证它是安全的。这些方法只同步对单个元素的访问。@VGR这显然不是真的。
 Collections.synchronizedList
Collections.synchronizedCollection
返回synchronizedCollection实例(或其子类),其中
toArray()
是同步的,因为其他方法访问源代码有助于澄清和解释文档,但以任何其他方式依赖您在那里找到的任何东西都是不明智的。如果它没有文档记录,那么它可以在没有警告的情况下更改。如果这样的更改是您肯定会很快注意到的,那么这可能是一个可接受的风险,b但是,我无法证明我的代码的线程安全性会因为这样的更改而丢失的风险是合理的。依赖代码比依赖文档更明智。在这种情况下,如果您依赖代码并注意到它没有充分同步,那么您的代码就不会因此而丢失,如果/当它被重新实现为线程安全,那么您就不会丢失任何东西。您正在努力g从我的建议阅读到代码提出建议,我没有这样做。对不起,但不是。对特定实现细节的观察,包括其代码,只告诉你该实现。依靠这些观察来回答比这更一般的问题不仅愚蠢,而且不安全t、 另一方面,例如OP的.API文档定义了每个正确实现的预期行为。依赖文档而不是实现是编程到接口的良好实践的一个实现。正如我前面所说的,您正在从我的阅读代码的建议跃升到对决定。我的回答从唯一正确的答案开始
是源集合线程安全的
。我对你的回答的唯一评论是-无论你的船漂浮什么。“源集合线程安全吗?”这既不是OP建议的操作是线程安全的必要条件,也不是充分条件。这不是必要条件,因为
ArrayList
构造函数本身可以提供所需的同步(尽管它实际上不这样做)。这是不够的,因为
ArrayList
构造函数可以使用原始集合中的方法,这些方法单独是线程安全的,但产生的结果不满足OP的条件。例如,它可以通过其
迭代器
获取集合的元素。
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    // ...
}
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);
    }
/**
 * 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();
/**
 * 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);
}
/**
 * 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;
}