跨对象的Java同步

mai*_*rgs 6 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;
    }

}
Run Code Online (Sandbox Code Playgroud)

因此,正如您在前面的示例中所看到的,我正在同步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;
    }

}
Run Code Online (Sandbox Code Playgroud)

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

Ord*_*ous 5

会有开销吗?是.

会有很多开销吗?要看.
如果只有一个线程,那么答案是"否",即使在这些古老的时期,无竞争同步也很快,据说自那以后它们变得更好了.

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

另一件需要注意的是,它们在不同的监视器上同步.第二个版本仅在1个监视器上同步,而原始 - 在两个上同步.

TL; DR

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