If I have 2 synchronized methods in the same class, but each accessing different variables, can 2 threads access those 2 methods at the same time? Does the lock occur on the object, or does it get as specific as the variables inside the synchronized method?
Example:
class X {
private int a;
private int b;
public synchronized void addA(){
a++;
}
public synchronized void addB(){
b++;
}
}
Can 2 threads access the same instance of class X performing x.addA(
) and x.addB()
at the same time?
If you declare the method as synchonized (as you're doing by typing
public synchronized void addA()
) you synchronize on the whole object, so two thread accessing a different variable from this same object would block each other anyway.If you want to synchronize only on one variable at a time, so two threads won't block each other while accessing different variables, you have synchronize on them separately in
synchronized ()
blocks. Ifa
andb
were object references you would use:But since they're primitives you can't do this.
I would suggest you to use AtomicInteger instead:
This example (although not pretty one) can provide more insight into locking mechanism. If incrementA is synchronized, and incrementB is not synchronized, then incrementB will be executed ASAP, but if incrementB is also synchronized then it has to 'wait' for incrementA to finish, before incrementB can do its job.
Both methods are called onto single instance - object, in this example it is: job, and 'competing' threads are aThread and main.
Try with 'synchronized' in incrementB and without it and you will see different results.If incrementB is 'synchronized' as well then it has to wait for incrementA() to finish. Run several times each variant.
If you have some methods which are not synchronized and are accessing and changing the instance variables. In your example:
any number of threads can access these non synchronized methods at the same time when other thread is in the synchronized method of the same object and can make changes to instance variables. For e.g :-
You need to avoid the scenario that non synchronized methods are accessing the instance variables and changing it otherwise there is no point of using synchronized methods.
In the below scenario:-
Only one of the threads can be either in addA or addB method but at the same time any number of threads can enter changeState method. No two threads can enter addA and addB at same time(because of Object level locking) but at same time any number of threads can enter changeState.
This might not work as the boxing and autoboxing from Integer to int and viceversa is dependant on JVM and there is high possibility that two different numbers might get hashed to same address if they are between -128 and 127.
From oracle documentation link
Making methods synchronized has two effects:
Have a look at this documentation page to understand intrinsic locks and lock behavior.
This will answer your question: On same object x , you can't call x.addA() and x.addB() at same time when one of the synchronized methods execution is in progress.
Yes, it will block the other method because synchronized method applies to the WHOLE class object as pointed .... but anyway it will block the other thread execution ONLY while performing the sum in whatever method addA or addB it enters, because when it finish ... the one thread will FREE the object and the other thread will access the other method and so on perfectly working.
I mean the "synchronized" is made precisely for blocking the other thread from accessing another while in a specific code execution. SO FINALLY THIS CODE WILL WORK FINE.
As a final note, if there is an 'a' and 'b' variables, not just an unique variable 'a' or whatever other name, there is no need to synchronize this methods cause it is perfectly safe accesing other var (Other memory location).
Will work as well