ArrayList 并发访问 [英] ArrayList concurrent access
问题描述
我知道 ArrayList
不是线程安全的,但我不确定这的确切含义.
I am aware that ArrayList
is not thread safe, but I'm unsure about the exact implications of this.
在 ThreadA
和 ThreadB
都使用 ArrayList
的情况下,哪些情况会导致问题并需要同步?
In the case of ThreadA
and ThreadB
both using an ArrayList
, which of these situations will cause issues and necessitate synchronization?
- 两个线程同时读取同一个索引
ThreadA
替换ThreadB
尝试同时访问的元素,假设您不关心ThreadB
是否变旧或新元素.
- Both threads simultaneously reading the same index
ThreadA
replacing an element whichThreadB
is attempting to access simultaneously, assuming that you don't care whether or notThreadB
gets the old or the new element.
推荐答案
两个线程同时读取同一个索引
Both threads simultaneously reading the same index
多个线程可以从共同的ArrayList
读取如果列表是由分叉ThreadA
和ThreadB
并且在分叉线程之前完全构造并加载了列表.
It is okay for multiple threads to be reading from common ArrayList
if the list was constructed by the thread that forked the ThreadA
and ThreadB
and the list is fully constructed and loaded before the threads were forked.
这样做的原因是一个线程和分叉它的线程的内存有一个happens-before保证.例如,如果 ThreadC
构建了 ArrayList
但 after ThreadA
和 ThreadB
是分叉,则不能保证 A 和 B 会完全看到 ArrayList
—— 如果有的话.
The reason for this is that there is a happens-before guarantee with a thread and the memory of the thread that forked it. If, for example, ThreadC
builds the ArrayList
but after ThreadA
and ThreadB
are forked, then there is no guarantee that A and B will fully see the ArrayList
-- if at all.
如果不是这种情况,则您需要同步列表.见下文.
If this is not the case then you will need to synchronize the list. See below.
ThreadA 更改了 ThreadB 尝试同时访问的元素,假设您不关心 ThreadB 是获取旧元素还是新元素.
ThreadA changing an element which ThreadB is attempting to access simultaneously, assuming that you don't care whether or not ThreadB gets the old or the new element.
一旦您在并发设置中讨论了对列表的修改,那么您必须在该列表上进行同步,否则无法保证会发布修改,并且有可能会部分发布该列表,这可能会导致数据异常.正如@Marko 所说,它的内部状态可能不一致.
Once you talk about modifications to the list in a concurrent setting, then you must synchronize on that list otherwise there is no guarantee that the modifications will be published and there are chances that the list could be partially published which could cause data exceptions. As @Marko puts it, its internal state may be inconsistent.
您可以使用专为少量更新和大量读取而设计的 CopyOnWriteArrayList
,使用 Collections.synchronizedList(...)
使您的列表受到保护,您可以始终在 synchronized
块中访问列表(对于所有写入 和 读取),或者您可以切换到使用并发集合,例如 ConcurrentSkipList
什么的.
You can either use a CopyOnWriteArrayList
which is designed for few updates and many reads, use Collections.synchronizedList(...)
to make your list be protected, you can access the list always in a synchronized
block (for all writes and reads), or you can switch to using a concurrent collection such as ConcurrentSkipList
or something.
ThreadA 改变了 ThreadB 试图同时访问的元素
ThreadA changing an element which ThreadB is attempting to access simultaneously
这有点模棱两可.例如,如果您正在谈论将对象存储在列表中,然后更改碰巧存储在列表中的对象,那么您将不会在 列表 上遇到同步问题,但您会对象有同步问题.如果列表的数据没有改变,那就没问题了.但是,如果您需要保护对象,则需要对象中的 AtomicReference
、volatile
字段列表或其他同步,以确保更改是在线程之间发布.
This is somewhat ambiguous. If you are talking about, for example, storing objects in the list and then changing the objects that happen to be stored in the list then you are not going to have a synchronization problem on the list but you will have a synchronization problem with the object. If the list's data is not changing then it will be fine. However, if you need to protect the object then either a list of AtomicReference<YourObject>
, volatile
fields in the object, or other synchronization is required to make sure the changes are published between the threads.
这篇关于ArrayList 并发访问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!