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

2022-09-03 15:30:35
Thread 1: Call list.add()
Thread 1: Exits list.add()
Thread 2: Call list.get(list.size()-1)

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

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

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

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

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

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


答案 2

在 or 关键字上使用 Collections.SynchronizedList() 与专用实现同步以进行添加以确保线程安全,list

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

推荐