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


当前回答

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


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

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

其他回答

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

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

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

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

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


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

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

大多数情况下,如果您需要并发列表,则它位于模型对象内部(因为您不应该使用抽象数据类型(如列表)来表示应用程序模型图中的节点),或者它是特定服务的一部分,您可以自己同步访问。

class MyClass {
  List<MyType> myConcurrentList = new ArrayList<>();
  void myMethod() {
    synchronzied(myConcurrentList) {
      doSomethingWithList;
    }
  }
}

通常这就足够让你继续下去了。如果你需要迭代,迭代列表的一个副本,而不是列表本身,并且只同步你复制列表的部分,而不是在你迭代它的时候。

另外,当并发处理一个列表时,通常要做的事情不仅仅是添加、删除或复制,这意味着该操作变得足够有意义,以保证它自己的方法,并且该列表成为一个特殊类的成员,仅表示这个具有线程安全行为的特定列表。

即使我同意需要一个并发列表实现和Vector / collections . synchronizelist (list)不做的技巧,你肯定需要像compareAndAdd或compareAndRemove或get(…, ifAbsentDo),即使您有ConcurrentList实现,开发人员在使用并发列表(和映射)时也经常会因为没有考虑真正的事务而引入错误。

在这些场景中,事务对于与并发ADT(抽象数据类型)交互的预期目的来说太小,总是导致我将列表隐藏在一个特殊的类中,并在方法级别上使用synchronized同步访问这个类对象方法。这是确保交易正确的唯一方法。

我已经看到了太多的错误,不能用其他方法来做——至少如果代码很重要,处理一些像金钱或安全或保证一些服务质量措施(例如至少发送一次且只发送一次消息)。

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
}