使用现有的同步Java类(Hashtable,StringBuffer,Vector)实现
或
在实现非同步Java类(HashMap,StringBuilder,ArrayList)时同步块
或
从Collections.synchronizedXXX()方法创建一个同步的集合对象,然后使用它(当然,我不能像这样同步StringBuilder。!!)
在多线程场景中,上述哪一种是实现同步而没有任何性能下降的最佳方法?
提前致谢。!!!
答案 0 :(得分:2)
最佳方法取决于您的代码正在尝试做什么以及您需要的原子级别。有时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'上的方法的每次调用都将包装在synchronized块中。您可以将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)是学习如何编写线程安全代码的绝佳资源。我强烈推荐它。我确定它在亚马逊上。