【问题标题】:Java ArrayList - Are add() calls from one thread always readable from another?Java ArrayList - 来自一个线程的 add() 调用是否总是可以从另一个线程读取?
【发布时间】:2015-04-16 10:20:01
【问题描述】:
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

【问题讨论】:

  • 如果是多线程环境,选择Collections.synchronizedList()COpyOnWriteArrayList。永远不要在 多线程 中做出假设
  • @Panther,它在多处理器环境下的表现如何,而缓存恰好可以提高性能
  • 你如何保证线程 1 将在线程 2 之前完成?
  • 即使添加了解释,这听起来仍然很可疑。是否保证在其他线程读取列表时不添加任何事件?删除事件是否有同样的保证?
  • 查看您的代码,我建议您使用ConcurrentLinkedDeque 并保留它。 Collections.synchronizedList痛苦地缓慢而CopyOnWriteArrayList 是可怕的你经常写,你似乎。

标签: java concurrency java.util.concurrent


【解决方案1】:

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

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

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

【讨论】:

  • 这就是我所怀疑的,尽管所有的答案都是相反的!我更新了我的帖子,解释了为什么我可以保证线程 1 将退出 add() 调用,以防万一发生任何变化。
  • @bcoughlan - 您的代码不是线程安全的。您没有做任何事情来确保一个线程所做的更改对另一个线程可见(我的意思是 join()synchronization )。
  • 附录:发生在是java中的一个定义术语,例如解释在官方教程中。同步块保证 happen before 关系,例如线程开始或结束或易失性读/写。还有一些关于可见性的常见误解:内存更改总是对其他线程可见,但更改的顺序可能与预期不同。 arraylist-size 可能已更改,但尚未更改的 array-entry。为了保证想要的排序,需要 happens-before 关系。
  • @I.K.我说的是我可以保证Thread 1会在线程2调用get()之前退出add()调用。
  • 两个值的更改最终(实际上是在瞬间)变得可见,但是同时读取这些值的另一个线程可能会看到比编写器的另一个更改顺序。即使作者的源代码或汇编代码另有说明。 (此外,还应该希望编译器/JIT 没有缓存寄存器中的值)。这里的关键始终是保证发生在之前。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 2015-07-17
    • 2013-07-16
    • 1970-01-01
    • 1970-01-01
    • 2012-06-11
    • 1970-01-01
    • 1970-01-01
    • 2014-09-01
    • 2014-08-21
    相关资源
    最近更新 更多