Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java synchronization across objects

I'm trying to make sure I understand the performance implications of synchronized in java. I have a couple of simple classes:

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;
    }

}

So, as you can see in the previous example, I'm synchronizing on ClassOne.setClassTwo and ClassTwo.setVal and ClassTwo.setVal2. What I'm wondering is if the performance is exactly the same if I remove the synchronization on ClassTwo.setVal and ClassTwo.setVal2, like so:

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;
    }

}

They are functionally equivalent in this scenario (assuming no other classes are using these classes), but wondering how much overhead (if any) there is in having more synchronization.

like image 730
mainstringargs Avatar asked Jul 29 '14 17:07

mainstringargs


2 Answers

Will there be overhead? Yes.

Will there be much overhead? Depends.
If there's one thread only, then the answer is "No", even in these ancient times uncontended synchronization was quick, supposedly they made it even better since.

So what happens if there is more than 1 thread? Well here's the problem: The 2 versions you posted are not functionally equivalent. Why? Because the submethods you are calling are public methods of a public class. Hence they can be called outside your setClassTwo and hence - have no synchronization.

The other thing to note is that they synchronize on different monitors. The second version synchronizes on 1 monitor only, while the original - on two.

TL;DR

Leave the synchronized on the methods that need to be synchronized, don't just expect the caller to synchronize (unless it's embedded in the class API). If the calling methods do the synchronization right, there will be no contention and the overhead will be very small, and if they fail to do it somehow (through someone calling your method directly, for example), then you get contention and larger overhead - but you still have thread safety.

like image 124
Ordous Avatar answered Oct 07 '22 01:10

Ordous


In your first case, you can create multiple threads and call setVal() on ClassTwo directly and not worry about memory inconsistencies (setVal() on ClassTwo is synchronized ). In your second case, you will have to be ready for unexpected results if you run multiple threads and call setVal() directly. Also, if you are always certain that setVal() will only be called from setClassTwo(), then I suggest you synchronize on Class2 instance using a synchronized block and keep setVal() and setVal2() as synchronized. Rule of thumb - only synchronize what can be accessed concurrently.

like image 24
TheLostMind Avatar answered Oct 07 '22 03:10

TheLostMind