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

bco*_*lan 15 java concurrency java.util.concurrent

Thread 1: Call list.add()
Thread 1: Exits list.add()
Thread 2: Call list.get(list.size()-1)
Run Code Online (Sandbox Code Playgroud)

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

编辑:对于那些对我能保证的原因感到好奇的人.我有一系列来自服务器的事件,如下所示:

Event A1
Event A2
Event A3
Event B
Run Code Online (Sandbox Code Playgroud)

事件由单个线程按顺序分派.我想捕获所有A事件的列表,所以我的代码看起来像这样:

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

connection.waitForEventB();

//Here I am doing operations on the eventAList
Run Code Online (Sandbox Code Playgroud)

The*_*ind 10

首先,您必须确保add()通过thread-1调用和get()通过thread-2 调用之间存在关系之前发生.完成通话和之前发生的完全不同.

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

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

  • 附录:*发生在*之前是java中定义的术语,例如在官方教程中解释.同步块保证<i>在</ i>关系之前发生,例如线程开始或结束或易失性读/写.还有一些关于可见性的常见误解:内存更改**始终对其他线程可见**,但更改的顺序可能与预期不符.arraylist-size可能已更改,但尚未更改数组条目.为了保证所需的订单,需要*之前发生*关系. (3认同)
  • 最终(实际上在瞬间)两个值变化都变得可见,但是同时读取值的另一个线程可能看到另一个变更顺序而不是写入者.即使作者的源代码或汇编代码另有说明.(此外,还应该希望编译器/ JIT没有缓存寄存器中的值).这里的关键始终是*在*给出之前发生的保证. (3认同)