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 可见。
在多线程环境中使用CopyOnWriteArrayList
或Collections.SynchronizedList()
。
在 list
或关键字上使用 Collections.SynchronizedList() 或与专用实现同步的关键字以确保线程安全,
public synchronized void addItem(Item item) {
list.add(item);
}
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 可见。
在多线程环境中使用CopyOnWriteArrayList
或Collections.SynchronizedList()
。
在 list
或关键字上使用 Collections.SynchronizedList() 或与专用实现同步的关键字以确保线程安全,
public synchronized void addItem(Item item) {
list.add(item);
}