Java ArrayList - 来自一个线程的 add() 调用是否始终可从另一个线程读取?

Java ArrayList - Are add() calls from one thread always readable from another?

Thread 1: Call list.add()
Thread 1: Exits list.add()
Thread 2: Call list.get(list.size()-1)

我有一个场景可以保证 Thread 1 将在 Thread 2 调用 get() 之前完成 add() 调用。在这种情况下,Thread 2 是否总能看到 Thread 1 所做的更改?或者内部 ArrayList 变量是否需要标记为 volatile?

编辑:对于那些好奇我为什么可以保证的人。我有来自服务器的一系列事件,如下所示:

Event A1
Event A2
Event A3
Event B

事件由单个线程按顺序分派。我想捕获所有 A 事件的列表,因此我的代码如下所示:

List<EventA> eventAList = new ArrayList<>();
connection.addListenerForEventAs(eventAList::add);

connection.waitForEventB();

//Here I am doing operations on the eventAList

首先,您必须确保线程 1 对 add() 的调用与对 get() 的调用之间存在 发生在 之前的关系通过线程 2。调用完成和发生在之前是完全不同的。

除非你这样做,否则你的代码将不是线程安全的。为什么?。线程 1 可能会在线程 2 调用 get() 之前完成对 add() 的调用。但是,Thread-2 不会对列表进行 本地复制 的保证是什么(保持方便)? add() 方法无法确保 happens-before。因此,无法保证第一个线程添加的值甚至被完全写入并且对线程 2 可见。

多线程环境中使用CopyOnWriteArrayListCollections.SynchronizedList()

list 或关键字上使用 Collections.SynchronizedList() 或与专用实现同步的关键字以确保线程安全,

public synchronized void addItem(Item item) {
    list.add(item);
}