【问题标题】:Effects of concurrent access to an unsynchronised Java ArrayList并发访问非同步 Java ArrayList 的影响
【发布时间】:2016-03-11 22:45:17
【问题描述】:

想象以下场景:

我有一个标准的 Java ArrayList<String>

ArrayList<String> 由多个线程访问,没有显式同步,受以下约束:

  1. 可能同时发生多个读取(可能与下面描述的写入同时发生)。所有读取调用ArrayList<String> 上的iterator() 方法并专门使用返回的Iterator<E>(迭代器不在线程之间共享)。在Iterator<String> 上调用的唯一方法是hasNext()next()(不调用remove() 方法)。
  2. 一个线程可以写入列表(可能与读取并发,但与其他写入不并发)。每次写入仅调用ArrayList<E> 上的add(String)remove(Object) 方法。

我知道以下是正确的:

  1. 读取线程可能会看到过时的数据。
  2. 读取线程可能会遇到ConcurrentModificationException

除了以上两个问题,还有什么问题吗?

我正在寻找具体的例子(形式的,如果xy为真,那么z会出现,其中z 不好)。它必须是可以在实践中实际发生的事情。请尽可能提供引用。

(我个人认为其他故障是可能的,但我一直受到挑战,无法提出为什么上述场景不适合生产代码的具体示例。)

【问题讨论】:

  • “除了以上两个问题,还有什么问题吗” -- 根据Javadoc,如果集合和/或迭代器没有快速失败,那么你对“任意的、不确定的行为”持开放态度,所以几乎一切皆有可能。

标签: java multithreading arraylist concurrency java-memory-model


【解决方案1】:

我希望您的读者或您的作者也会收到 ArrayIndexOutOfBounds 异常或空指针异常,因为他们可能会看到底层数组的不一致状态。

您确实受制于 ArrayList 类的详细实现——它可能因环境而异。 JVM 可能会使用本机代码实现该类,这可能会在不同步的情况下读取时导致更严重的未定义行为(JVM 崩溃)。

我会从ConcurrentModificationException reference page的文本中添加这个:

请注意,不能保证快速失败的行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。快速失败操作会尽最大努力抛出 ConcurrentModificationException。因此,编写一个依赖此异常来确保其正确性的程序是错误的:ConcurrentModificationException 应该仅用于检测错误。

简而言之,除了陈旧的数据和 ConcurrentModificationException 之外,您不能依赖任何不好的事情发生。

【讨论】:

  • 肯定 ArrayList 是字节码,而不是与给定 JRE 捆绑的本机代码?
  • @beresfordt 至少,数组索引访问(读取和写入)肯定是注释字节码,它们的行为在这里至关重要。同上参考访问等。
  • 不是不同意,只是要求澄清一个具体的说法
  • @beresfordt -- 我还没有看到 ArrayList 的本机实现 -- 但没有什么可以阻止它
  • 你见过java标准库中任何类的本地实现吗?
猜你喜欢
  • 2020-09-11
  • 1970-01-01
  • 2015-01-03
  • 1970-01-01
  • 2016-03-03
  • 1970-01-01
  • 2012-08-05
  • 1970-01-01
  • 2016-04-15
相关资源
最近更新 更多