java - `ArrayList::get` 是线程安全的吗?

标签 java multithreading arraylist thread-safety

我知道修改 ArrayList让它不thread-safe .

➠ 但是,如果 ArrayList 被修改,可能通过调用 Collections.unmodifiableList 来保护, 正在调用 ArrayList::get线程安全?

例如,可以将 ArrayList 传递给 Java Stream 吗?并行处理其元素?

最佳答案

But if the ArrayList is not being modified is calling ArrayList::get thread-safe?

不,它不是线程安全的。

如果您执行以下操作,则会出现问题:

  1. 线程 A 创建并填充列表。
  2. 线程 A 将对列表的引用传递给线程 B(没有发生在关系)
  3. 线程 B 在列表中调用 get

除非在 1 和 3 之间有适当的 happens before 链,否则线程 B 可能会看到陈旧的值......偶尔......在某些平台上在某些工作负载下。

有很多方法可以解决这个问题。例如,如果线程 A 在步骤 1 之后启动了线程 B,那么就会有一个 happens before。类似地,如果 A 通过正确同步的 setter/getter 调用或 volatile 变量将列表引用传递给 B,则会发生之前的情况。

但底线是(只是)不更改列表不足以使其成为线程安全的。


... perhaps protected by a call to Collections.unmodifiableList

Collections.unmodifiableList 的创建应该提供happens before 关系...前提是您通过包装而不是直接通过ArrayList 访问列表: :get.


For example, can an ArrayList be passed to a Java Stream for parallel-processing of its elements?

这是一个特定的情况。流机制将提供happens before 关系。 前提是它们按预期使用。这很复杂。

这来自Spliterator 接口(interface)javadoc .

"Despite their obvious utility in parallel algorithms, spliterators are not expected to be thread-safe; instead, implementations of parallel algorithms using spliterators should ensure that the spliterator is only used by one thread at a time. This is generally easy to attain via serial thread-confinement, which often is a natural consequence of typical parallel algorithms that work by recursive decomposition. A thread calling trySplit() may hand over the returned Spliterator to another thread, which in turn may traverse or further split that Spliterator. The behaviour of splitting and traversal is undefined if two or more threads operate concurrently on the same spliterator. If the original thread hands a spliterator off to another thread for processing, it is best if that handoff occurs before any elements are consumed with tryAdvance(), as certain guarantees (such as the accuracy of estimateSize() for SIZED spliterators) are only valid before traversal has begun."

换句话说,线程安全是 Spliterator 实现和 Stream 实现的共同责任。

考虑这一点的简单方法是“奇迹发生了”......因为如果没有发生,那么并行流将无法使用。

但请注意,Spliterator 根本不需要使用 ArrayList::get

关于java - `ArrayList::get` 是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46614481/

相关文章:

java - JAX-RS 处理可变数量的 FormParam

java - Java多线程/并发的核心阅读资源?

java - Hashmap 中的 NullPointerException 错误

java - 获取两种颜色之间的中值颜色

java - 如何在 Android 中通过动态创建为按钮提供 id?

Java - 强制执行已实现的方法

python - 在 Python 中安排超时

iphone - Objective-C中的静态变量和多个线程

Java继承ArrayList类型in方法

java - 正则表达式数组列表