最佳方法取决于您的代码到底要做什么以及您需要的原子性级别。有时Collections.synchronizedWhatever 很好;有时您需要自己进行同步。
就性能而言,您只需确保将输入的synchronized 块的数量降至最低。差别不大
(example A)
List l = Collections.synchronizedList(originalList);
l.add(something);
和
(example B)
synchronized (originalList) {
originalList.add(something);
}
因为它们都进入了一个同步块。然而:
(example C)
List l = Collections.synchronizedList(originalList);
l.add(something);
int index = l.indexOf(something);
将进入两个同步块,而
(example D)
synchronized (originalList) {
originalList.add(something);
int index = originalList.indexOf(something);
}
只会输入一个同步块。当然,它在该块中花费的时间更长,因此可能会增加争用,但是 add 和 indexOf 现在的行为就像一个单一的原子操作。这可能是也可能不是您想要的:它完全取决于应用程序。
编辑:回答 Deepak 的问题:
示例 C 中的 'synchronizedList' 意味着对 'l' 上的方法的每次调用都将包装在同步块中。你可以认为 C 是这样做的:
synchronized (originalList) {
originalList.add(something);
}
synchronized (originalList) {
int index = originalList.indexOf(something);
}
这里有一些额外的成本,但除非它位于代码的性能关键部分,否则它可能不会成为问题。我建议您在考虑优化代码之前多考虑确保代码行为正确。很难获得正确的线程安全代码,所以要非常小心你如何编写东西。例如,在 C 中,“l.add(something)”和“l.indexOf(something)”之间可能存在竞争条件。 D 没有相同的竞争条件,因为这两个操作都在一个同步块内。
Brian Goetz 的书(Java Concurrency in Practice)是学习如何编写线程安全代码的绝佳资源。我强烈推荐它。我确定它在亚马逊上。