Java - ArrayList构造函数的线程安全性

and*_*oot 9 java collections concurrency

我正在看这段代码.此构造函数委托给本机方法"System.arraycopy"

它是安全的吗?我的意思是它可以抛出一个ConcurrentModificationException吗?

public Collection<Object> getConnections(Collection<Object> someCollection) {
    return new ArrayList<Object>(someCollection);
}
Run Code Online (Sandbox Code Playgroud)

如果被复制的集合是ThreadSafe,例如CopyOnWriteArrayList,它会有什么不同吗?

public Collection<Object> getConnections(CopyOnWriteArrayList<Object> someCollection) {
    return new ArrayList<Object>(someCollection);
}
Run Code Online (Sandbox Code Playgroud)

编辑:我知道ThreadSafe!= ConcurrentModificationException.我试图在某个时间点拍摄数据快照.因此,如果另一个线程通过副本中途写入someCollection,我不在乎结果是否有新对象.我只是不希望它抛出ConcurrentModificationException或更糟

Ste*_*n C 7

此构造函数委托给本机方法"System.arraycopy"

其实,它调用toArray()someCollection.System.arraycopy如果someCollection是,那最终会调用ArrayList.对于其他集合类型,将以其他方式创建数组.

它是安全的吗?

没有.

我的意思是它可以抛出一个ConcurrentModificationException吗?

如果它是一个ArrayList它不会扔ConcurrentModificationException... 但这不会使它线程安全!!

例如,如果一个不同的线程调用set(obj, pos)someCollection,而你的线程调用此构造,那么你的新创建的内容ArrayList是不可预测的.


Joe*_*ley 5

线程安全和ConcurrentModificationException是不同的概念.线程安全对象是多个线程可以同时调用其方法的对象,并且保证对象中保存的数据不会被破坏(例如:http://thejavacodemonkey.blogspot.com/2007/08/making- your-java-class-thread-safe.html).例如,当您正在迭代集合并且集合发生更改时,会发生ConcurrentModificationException.更改可能来自不同的线程或同一个线程.

在构造函数中,如果另一个线程someCollection在构造函数复制时发生更改,则可能导致未定义的行为(即新集合中的数据损坏,因为集合不是线程安全的),或者是ConcurrentModificationException(如果集合确实检测到)并发修改,但这不能保证,因为它不是线程安全的...... :-)

如果构造函数要使用a Collection<Object>,则需要确保其他线程在构造函数返回之前不会修改集合.

另一方面,CopyOnWriteArrayList是线程安全的,保证不会抛出ConcurrentModificationException,因此您应该以这种方式安全地执行此操作,而无需编写额外的同步代码.


Kev*_*ion 5

您的问题是,是否可以安全地获取可能正在被另一个线程进行并发修改的集合的快照new ArrayList<Foo>(thatCollection)。答案是:只要thatCollection本身是线程安全的,就可以。因此,如果它是CopyOnWriteArrayListsynchronizedListVector,则它不是线程安全的,例如,如果它是另一个ArrayList,则不能很好地处理。(将会发生的事情可能比ConcurrentModificationException。更糟。)

原因是ArrayList构造函数仅对另一个集合(其toArray方法)进行单个原子调用。因此,它本质上享受该方法本身具有的线程安全保证。它并非总是像这样实现,而现在正是出于这个原因。我们在Guava中使用进行相同的操作ImmutableList.copyOf