集合中最佳的Java线程安全锁机制是什么?

4

在Java中控制对集合的多次访问的最不慢的线程安全机制是什么?

我正在将对象添加到一个集合的顶部,但我非常不确定哪种集合会性能最佳。vector还是queue?我最初认为ArrayList很快,但我进行了一些实验,结果非常缓慢。

编辑:在我的插入测试中,使用volatile声明的Vector似乎是最快的?


5
典型操作究竟是什么?您需要随机访问吗?读取次数比写入次数多吗?在开头或结尾添加/删除元素? - Michael Borgwardt
1
非常规律地在末尾添加元素,只保留第一个和最后一个元素以外的所有元素。不进行随机插入或删除。我认为写入操作比读取操作更频繁。 - Jason
2
看看 java.util.concurrent 包。不难找到一个。我个人喜欢 ConcurrentLinkedQueue 和 CopyOnWriteArrayList... - user166390
读取什么类型的数据?(从开头、结尾还是随机位置中间?) - Jason S
ConcurrentLinkedQueue 的 size 方法不以恒定时间运行。不知道这对您是否有影响。 - LazyCubicleMonkey
显示剩余2条评论
6个回答

6

5

最好的算法尽可能避免共享状态。听起来你对Java的多线程编程还很陌生。为什么不选择一些你知道肯定正确的东西...然后看看有多少同步,再看看是否有问题...然后看看是否能找到更快的方法。


4

确切的操作应该决定使用什么。然而,由于容器在很大程度上是一种抽象类型,因此编写它使其可靠工作,然后进行剖析,确保功能要求,根据需要进行优化等等 :)

通常,我主要使用"并发集合"是用于在线程之间传输对象的队列。在这种情况下,我从ConcurrentLinkedQueue开始,原因是喜欢“无锁”算法(但这并不意味着它会更快:-)。

一般来说,队列和/或链表是一个很好的数据结构,可以将内容附加到末尾。根据情况,包括特定的使用模式,例如线程争用、删除的项目数量、如何删除项目等等,除了开始/结束之外,“快速杀死”所有项目可能会更快地通过清除(AbstractQueue的一部分)和重新添加项目来完成——ConcurrentLinkedQueue允许同时检查/操作头部和尾部。然而,我建议“保持简单”,写入“特定接口合同”,并“仅使用当前方法”,直到有强有力的证据表明未满足功能需求为止。
至于性能,它实际上取决于特定的用例/操作数据结构特征和数据结构实现。在某些情况下,ArrayList可能比Vector慢,并且确实有记录。如果这种性能有所差异,那么似乎有些可疑。Java Best Practices – Vector vs ArrayList vs HashSet中的文章包含了一篇不错的阅读材料。请注意评论。 编辑:请记住,“并发”数据结构通常只意味着单个操作(方法调用)是原子的(在一些奇怪的情况下可能不是所有操作!)。仍然可能需要实现大范围的同步或其他方法来达到所需的线程安全级别。也就是说,h.putIfAbsent(k,v)(来自ConcurrentHashMap)与if (!h.containsKey(k)) { h.put(k, v); }不同--举个例子,像“清除然后添加”方法中提到的问题也适用于这种情况。

编码愉快。


0
也许你可以编写自己的 LinkedList 实现?
Java 集合中的 LinkedList 只有一个 current 指针,如果你想要一个同时具有 head 和 tail 的 LinkedList,那么你可以自己实现。
此外,你还可以将其包裹在 Collections.synchronizedList(...) 中。

我感到困惑,因为从我的测试结果来看,对于仅插入操作,Vector似乎是最快的容器?但是我原本以为它是同步的,应该比一些非同步的容器更慢? - Jason
向量是同步的。我相信它使用类似于System.arrayCopy(...)的东西,速度非常快。然而,通过自定义LinkedList的实现,您可以仅更改头和尾指针以删除除第一个和最后一个元素之外的所有元素。但这对于随机访问来说可能不太好。 - LazyCubicleMonkey

0

嗯,如果我正确理解了“使用volatile的向量”这个评论,您可能并不完全理解同步的含义。Volatile只适用于对Vector的引用;而由于Vector本身是同步的,因此它将是多余的。

但从根本上讲,您真的认为由于同步(用于容器访问)而导致的性能差异足以让您担心吗?如果是这样,您应该能够通过分析(访问和/或变异的热点)看到效果。我并不是说没有这种情况发生,但它们并不特别常见。


0

ConcurrentSkipListMap/Set - 但你必须知道如何/何时使用它。CopyOnWriteArrayList是另一个很好的解决方案(同样需要知道为什么要使用它)。

编辑:在我的插入测试中,使用volatile声明的Vector似乎是最快的?

那只是不酷而且完全没有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接