控制Java集合的并发访问的最佳方法

Phi*_*Lho 25 java collections concurrency

我应该使用旧的同步Vector集合,具有同步访问的ArrayList还是Collections.synchronizedList或其他一些并发访问的解决方案?

我没有在相关问题或我的搜索中看到我的问题(使你的收藏品线程安全吗?不一样).

最近,我不得不对应用程序的GUI部分进行单元测试(基本上使用API​​来创建框架,添加对象等).由于这些操作的调用速度比用户快得多,因此它显示了尝试访问尚未创建或已删除的资源的方法的许多问题.

在EDT中发生的一个特殊问题来自于在另一个线程中改变它时在一个链接的视图列表中行走(在其他问题中获得ConcurrentModificationException).不要问我为什么它是一个链表而不是一个简单的数组列表(更少,因为我们通常在0或1视图里面...),所以我在我的问题中采用了更常见的ArrayList(因为它有一个年长的堂兄).

无论如何,我不太熟悉并发问题,我查了一下信息,想知道在旧的(可能是过时的)Vector(它有设计的同步操作),ArrayList和synchronized (myList) { }周围关键部分(添加/删除)之间做出选择/ walk operations)或使用Collections.synchronizedList返回的列表(甚至不确定如何使用后者).

我最终选择了第二个选项,因为另一个设计错误是暴露对象(getViewList()方法...)而不是提供使用它的机制.

但其他方法的优缺点是什么?


[编辑]这里有很多好的建议,很难选择一个.我会选择更详细的,提供链接/食物的想法...... :-)我也喜欢Darron的.

总结一下:

  • 正如我所怀疑的那样,Vector(及其邪恶的双胞胎,也可能是Hashtable)在很大程度上已经过时了,我看到有人说它的旧设计不如新系列那么好,超出了同步的慢速,即使在单线程环境中也是如此.如果我们保留它,主要是因为较旧的库(以及Java API的一部分)仍然使用它.
  • 与我的想法不同,Collections.synchronizedXxxx并不比Vector更现代(它们似乎是Collections的当代,即Java 1.2!)而实际上并不是更好.很高兴知道.简而言之,我也应该避免它们.
  • 毕竟,手动同步似乎是一个很好的解决方案.可能存在性能问题,但在我的情况下并不重要:对用户操作,小型收集,不经常使用的操作.
  • java.util.concurrent包值得记住,尤其是CopyOnWrite方法.

我希望我做对了...... :-)

Ale*_*ler 23

Vector和Collections.synchronizedList()返回的List在道德上是一回事.我会认为Vector有效(但实际上)不推荐使用,而且总是更喜欢同步List.唯一的例外是需要Vector的旧API(特别是JDK中的API).

使用裸ArrayList并独立同步使您有机会更精确地调整同步(通过在互斥块中包含其他操作或通过在一个原子操作中组合对List的多个调用).不利的一面是,可以编写访问同步之外的裸ArrayList的代码,该代码被破坏.

您可能需要考虑的另一个选项是CopyOnWriteArrayList,它将为您提供线程安全,如Vector和synchronized ArrayList,以及不会抛出ConcurrentModificationException的迭代器,因为它们正在处理数据的非实时快照.

您可能会发现这些有关这些主题的最新博客有趣:


Dar*_*ron 13

我强烈推荐" Java Concurrency in Practice " 一书.

每个选择都有优点/缺点:

  1. 矢量 - 被认为是"过时的".与更多主流馆藏相比,它可能得到的关注和错误修复更少.
  2. 你自己的同步块 - 很容易弄错.通常表现出比下面的选择更差的表现.
  3. Collections.synchronizedList() - 由专家完成的选择2.这仍然是不完整的,因为需要原子的多步操作(获取/修改/设置或迭代).
  4. 来自java.util.concurrent的新类 - 通常比选择3具有更高效的算法.类似的关于多步操作的注意事项适用,但通常会提供帮助您的工具.


jcr*_*ey3 10

我想不出永远喜欢一个很好的理由VectorArrayList.a上的列表操作Vector是同步的,这意味着多个线程可以安全地更改它.就像你说的,ArrayList的操作可以使用同步Collections.synchronizedList.

请记住,即使使用同步列表,ConcurrentModificationExceptions如果在另一个线程修改集合时迭代该集合,您仍会遇到.因此,从外部协调该访问(第二个选项)非常重要.

用于避免迭代问题的一种常用技术是迭代集合的不可变副本.看到Collections.unmodifiableList


ric*_*chs 7

我会一直去java.util.concurrent(http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-summary.html)包,看看是否有任何合适的系列.如果对列表进行少量更改但迭代次数较多,则java.util.concurrent.CopyOnWriteArrayList类很好.

我也不相信Vector和Collections.synchronizedList会阻止ConcurrentModificationException.

如果你没有找到合适的集合,那么你必须进行自己的同步,如果你不想在迭代时持有锁,你可能需要考虑制作副本并迭代副本.