跨对象的Java同步

时间:2014-07-29 17:33:46

标签: java synchronization

我试图确保我理解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;
    }

}

它们在这种情况下在功能上是等效的(假设没有其他类正在使用这些类),但是想知道有多少开销(如果有的话)有更多的同步。

3 个答案:

答案 0 :(得分:5)

会有开销吗?是。

会有很多开销吗?依赖。
如果只有一个线程,那么答案是"否",即使在these ancient times无竞争同步很快,据说他们自那以后做得更好。

那么如果有超过1个线程会发生什么?那么问题就在于:您发布的2个版本功能相同。为什么?因为您调用的子方法是公共类的公共方法。因此,它们可以在setClassTwo之外调用,因此 - 没有同步。

另外需要注意的是,他们会在不同的监视器上同步 。第二个版本仅在1个监视器上同步,而原始 - 在两个版本上同步。

TL; DR

synchronized保留在需要同步的方法上,不要期望调用者同步(除非它嵌入在类API中)。如果调用方法执行正确的同步,则不存在争用,并且开销将非常小,并且如果它们无法以某种方式执行(例如,通过直接调用您的方法的人),那么您将获得争用和更大的开销 - 但你仍然有线程安全。

答案 1 :(得分:1)

第一个的情况下,您可以创建多个线程并直接在ClassTwo上调用setVal(),而不用担心内存不一致(setVal()上的ClassTwo是< em> synchronized )。在 second 的情况下,如果您运行多个线程并直接调用setVal(),则必须为意外结果做好准备。另外,如果您始终确定只会从setVal()调用setClassTwo(),那么我建议您使用synchronized块在Class2实例上同步并保留{ {1}}和setVal()已同步。经验法则 - 仅同步可以同时访问的内容

答案 2 :(得分:1)

同步方式还取决于您计划如何使用ClassTwo。如果写入很少,并且读取频繁,则readwritelock可以在更大的范围内提供更好的性能。只有在写入正在进行时才会阻止读取,因为读取锁定由多个读取器线程共享,而写入会阻塞所有写入,直到写入完成。

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReadWriteLock.html

我希望这会有所帮助。