我如何创建一个并发的列表实例,在那里我可以通过索引访问元素?JDK是否有我可以使用的类或工厂方法?


当前回答

在java.util.concurrent中有一个并发列表实现。特别是CopyOnWriteArrayList。

其他回答

在java.util.concurrent中有一个并发列表实现。特别是CopyOnWriteArrayList。

因为获取位置和从给定位置获取元素的行为自然需要一些锁定(您不能让列表在这两个操作之间发生结构变化)。

并发收集的思想是,每个操作本身都是原子的,可以在没有显式锁定/同步的情况下完成。

因此,从给定的List中获取位置n的元素作为原子操作在期望并发访问的情况下没有太大意义。

免责声明:这个答案发表于2011年,在JDK 5之前,也在更高级和最优的并发api之前。因此,虽然下面的方法可以工作,但它不是最好的选择。


如果你需要的只是简单的调用同步,你可以很好地使用Collections.synchronizedList(List):

 List<Object> objList = Collections.synchronizedList(new ArrayList<Object>());

你有这些选择:

Collections.synchronizedList(): you can wrap any List implementation (ArrayList, LinkedList or a 3rd-party list). Access to every method (reading and writing) will be protected using synchronized. When using iterator() or enhanced for loop, you must manually synchronize the whole iteration. While iterating, other threads are fully blocked even from reading. You can also synchronize separately for each hasNext and next calls, but then ConcurrentModificationException is possible. CopyOnWriteArrayList: it's expensive to modify, but wait-free to read. Iterators never throw ConcurrentModificationException, they return a snapshot of the list at the moment of iterator creation even if the list is modified by another thread while iterating. Useful for infrequently updated lists. Bulk operations like addAll are preferred for updates - the internal array is copied less many times. Vector: very much like synchronizedList(new ArrayList<>()), but iteration is synchronized too. However, iterators can throw ConcurrentModificationException if the vector is modified by another thread while iterating.

其他选项:

Queue or Deque might be an alternative if you only add/remove at the ends of the list or iterate it. Queue allows only adding at one end and removing from the other end, Deque allows adding and removing on both ends. There's no access by index. There are multiple implementations with better concurrency properties than any List can provide. Look at "All Known Implementing Classes" in the Queue javadoc, those implementations that are in the java.util.concurrent package are concurrent. You can also have a look at JCTools, it contains faster queue implementations specialized for single consumer or single producer. Collections.unmodifiableList(): wait-free, thread-safe, but non-modifiable List.of & List.copyOf: Another non-modifiable list in Java 9 and later.

ConcurrentLinkedQueue

如果您不关心是否具有基于索引的访问,而只想要List的插入顺序保持特性,那么可以考虑java.util.concurrent.ConcurrentLinkedQueue。因为它实现了Iterable,一旦你添加完所有的项,你可以使用增强的for语法循环内容:

Queue<String> globalQueue = new ConcurrentLinkedQueue<String>();

//Multiple threads can safely call globalQueue.add()...

for (String href : globalQueue) {
    //do something with href
}