[英]Java synchronization across objects
我正在努力确保我理解java中synchronized的性能影响。 我有几个简单的类:
public class ClassOne {
private ClassTwo classTwo = new ClassTwo();
public synchronized void setClassTwo(int val1, int val2) {
classTwo.setVal(val1);
classTwo.setVal2(val2);
}
public static void main(String[] args) {
ClassOne classOne = new ClassOne();
classOne.setClassTwo(10, 100);
}
}
public class ClassTwo {
private int val;
private int val2;
public synchronized void setVal(int val) {
this.val = val;
}
public synchronized void setVal2(int val2) {
this.val2 = val2;
}
}
因此,正如您在前面的示例中所看到的,我正在同步ClassOne.setClassTwo和ClassTwo.setVal以及ClassTwo.setVal2。 我想知道的是,如果我在ClassTwo.setVal和ClassTwo.setVal2上删除同步,性能是否完全相同,如下所示:
public class ClassTwo {
private int val;
private int val2;
public void setVal(int val) {
this.val = val;
}
public void setVal2(int val2) {
this.val2 = val2;
}
}
它们在这种情况下在功能上是等效的(假设没有其他类正在使用这些类),但是想知道在进行更多同步时有多少开销(如果有的话)。
会有开销吗? 是。
会有很多开销吗? 要看。
如果只有一个线程,那么答案是“否”,即使在这些古老的时期,无竞争同步也很快,据说自那以后它们变得更好了。
那么如果有超过1个线程会发生什么? 那么这就是问题所在:您发布的2个版本在功能上并不相同。 为什么? 因为您调用的子方法是公共类的公共方法。 因此,它们可以在setClassTwo
之外调用,因此 - 没有同步。
另一件需要注意的是,它们在不同的监视器上同步。 第二个版本仅在1个监视器上同步,而原始 - 在两个上同步。
TL; DR
将synchronized
保留在需要synchronized
的方法上,不要只期望调用者同步(除非它嵌入在类API中)。 如果调用方法执行正确的同步,则不存在争用,并且开销将非常小,并且如果它们无法以某种方式执行(例如,通过直接调用您的方法的人),那么您将获得争用和更大的开销 - 但你仍然有线程安全。
在第一种情况下,您可以创建多个线程并直接在ClassTwo上调用setVal()
而不用担心内存不一致( setVal()
上的ClassTwo
setVal()
被同步 )。 在第二种情况下,如果您运行多个线程并直接调用setVal()
,则必须为意外结果做好准备。 另外,如果你总是肯定的是, setVal()
将只从被称为setClassTwo()
那么我建议你同步 Class2
使用synchronized块实例,并保持setVal()
和setVal2()
的同步 。 经验法则 - 仅同步可同时访问的内容 。
同步方式还取决于您计划如何使用ClassTwo。 如果写入很少,并且读取频繁,则readwritelock可以在更大的范围内提供更好的性能。 只有在写入正在进行时才会阻止读取,因为读取锁定由多个读取器线程共享,而写入会阻止所有写入直到写入完成。
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReadWriteLock.html
我希望这有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.