【发布时间】:2014-12-12 23:29:21
【问题描述】:
我需要一个类似 ArrayList 的结构,只允许以下操作
get(int index)add(E element)set(int index, E element)iterator()
由于很多地方都使用了迭代器,所以使用Collections#synchronizedList 太容易出错了。该列表可以增长到几千个元素并且被大量使用,所以我很确定CopyOnWriteArrayList 会太慢。我将从它开始以避免过早的优化,但我敢打赌它不会很好地工作。
大多数访问将是单线程读取。所以我在问什么是正确的数据结构。
我虽然将synchronizedList 包装在提供同步迭代器的东西中会做,但它不会因为ConcurrentModificationException。关于并发行为,我显然需要后续读取和迭代器可以看到所有更改。
迭代器不必显示一致的快照,它可能会或可能不会通过set(int index, E element) 看到更新,因为此操作仅用于将项目替换为其更新版本(包含一些附加信息,这是无关紧要的对于迭代器的用户)。这些项目是完全不可变的。
我清楚地说明了为什么CopyOnWriteArrayList 不会这样做。 ConcurrentLinkedQueue 毫无疑问,因为它缺少索引访问。我只需要几个操作而不是完全成熟的ArrayList。因此,除非任何与 java 并发列表相关的问题与this question 重复,否则这个问题不是。
【问题讨论】:
-
你可能想试试 Clojure 的
PersistentVector,它也是copy-on-write,但不是一个简单的整体数组;而是一个宽而浅的数组树。在我链接到的源代码的末尾,您会找到测试代码。 -
@skaffman 您能否在关闭之前阅读该问题?查看我的更新。
-
@MarkoTopolnik 这可行,但代码看起来很奇怪。它还增加了我不关心的操作所需的一些开销。顺便说一句,你能投票重新开放吗?恕我直言,这个模组的阅读速度有点太快了。
-
那是他的粗心大意 :) 是的,Rich Hickey 有一种特殊的编码风格,但您可能仍想重用该代码,删除所有多余的内容。我认为 Rich 的方法非常好。
-
更多关于用例和目标的信息会很有帮助。速度似乎是其中之一,数据完整性也是如此。
标签: java arraylist concurrency