If I synchronized two methods on the same class, can they run simultaneously?
Asked Answered
C

12

223

If I synchronized two methods on the same class, can they run simultaneously on the same object? For example:

class A {
    public synchronized void methodA() {
        //method A
    }

    public synchronized void methodB() {
        // method B
    }
}

I know that I can't run methodA() twice on same object in two different threads. same thing in methodB().

But can I run methodB() on different thread while methodA() is still running? (same object)

Calamint answered 15/3, 2013 at 17:35 Comment(0)
W
198

Both methods lock the same monitor. Therefore, you can't simultaneously execute them on the same object from different threads (one of the two methods will block until the other is finished).

Watershed answered 15/3, 2013 at 17:36 Comment(7)
I had a add on to this question. Suppose both method are static now methodA is called using Class while methodB is called using object like A.methodA() in t1 and obj.methodB() in t2. What will happen now, will they block????Waynant
@amod0017: obj.methodB() is synonymous to A.methodB() when methodB() is static. Therefore yes, they will block (on the class's, not the object's, monitor).Watershed
will try and get back to it. :)Waynant
@Watershed So even if both method are static and 2 threads t1 and t2 on same object tries to call methodA() and methodB() simultaneously then only 1 (say t1) thread will execute and the other thread has to wait until t1 releases lock ?Finnegan
Have in mind that static methods use lock on .class object. So if you have class A {static synchronized void m() {} }. And then one thread calls new A().m() it acquires lock on new A() object. If then another thread calls A.m() it ENTERS THE METHOD NO PROBLEM because what it looks for is lock on A.class object while NO THREADS possess this kind of lock. So even though you declared method synchronized it actualy IS accessed by two different threads AT THE SAME TIME. Thus: never use object references to call static methodsBamford
@AlexSemeniuk if I use private final Object lock = new Object(); and then use public void m1(){synchronized(lock){}} and public void m2(){synchronized(lock){}} and call both m1 and m2 from threads t1 and t2 created on different objects, will t1 and t2 not be able to access m1 and m2 simultaneously? IMO they should not be. Please correct me If I am wrong. Thanks.Compander
Yes, it would be synchronized, since you are using the same synchronization object. My comment was related to the specifics of using synchronized keyword in method declarations.Bamford
O
152

In the example methodA and methodB are instance methods (as opposed to static methods). Putting synchronized on an instance method means that the thread has to acquire the lock (the "intrinsic lock") on the object instance that the method is called on before the thread can start executing any code in that method.

If you have two different instance methods marked synchronized and different threads are calling those methods concurrently on the same object, those threads will be contending for the same lock. Once one thread gets the lock all other threads are shut out of all synchronized instance methods on that object.

In order for the two methods to run concurrently they would have to use different locks, like this:

class A {
    private final Object lockA = new Object();
    private final Object lockB = new Object();

    public void methodA() {
        synchronized(lockA) {
            //method A
        }
    }

    public void methodB() {
        synchronized(lockB) {
            //method B
        }
    }
}

where the synchronized block syntax allows specifying a specific object that the executing thread needs to acquire the intrinsic lock on in order to enter the block.

The important thing to understand is that even though we are putting a "synchronized" keyword on individual methods, the core concept is the intrinsic lock behind the scenes.

Here is how the Java tutorial describes the relationship:

Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.

Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.

The purpose of locking is to protect shared data. You would use separate locks as shown in the example code above only if each lock protected different data members.

Orsay answered 15/3, 2013 at 17:39 Comment(3)
so in this example the lock is on the lockA\lockB objects and not on the class A? Is this a class level locking example?Restrainer
@Nimrod: it's locking on lockA and on lockB objects and not on the instance of A. nothing here is locking on a class. class-level locking would mean getting the lock on a class object, using something like static synchronized or synchronized (A.class)Orsay
Here is the link to the java tutorial explaining exactly what is answered here.Tempest
D
20

Java Thread acquires an object level lock when it enters into an instance synchronized java method and acquires a class level lock when it enters into static synchronized java method.

In your case, the methods(instance) are of same class. So when ever a thread enters into java synchronized method or block it acquires a lock(the object on which the method is called). So other method cannot be called at the same time on the same object until the first method is completed and lock(on object) is released.

Dapsang answered 15/3, 2013 at 17:47 Comment(1)
if I have two threads on two different instances of the class then they will be able to execute both methods simultaneously such that one thread calls one synchronized method and the other one calls the second synchronized method. If my understanding is correct then can i use private final Object lock = new object(); with synchronized to allow only one thread to be able to execute either of the methods? ThanksCompander
H
15

In your case you synchronized two method on the same instance of class. So, these two methods can't run simultaneously on different thread of the same instance of class A. But they can on different class A instances.

class A {
    public synchronized void methodA() {
        //method A
    }
}

is the same as:

class A {
    public void methodA() {
        synchronized(this){
            // code of method A
        }
    }
}
Hydrobomb answered 15/3, 2013 at 17:49 Comment(3)
what if I define a lock as private final Object lock = new Object(); and now use lock with synchronized block in two methods then will your statement hold true? IMO since Object is the parent class of all the objects so even if the threads are on different instance of the class, only one can access the code inside synchronized block at a time. Thanks.Compander
If you define "private final Object lock" in the class and synchronize with it, you fill have lock per class instance, so, it will behaves the same as synchronized(this).Hydrobomb
Yes, Object is a parent for all classes, but "lock" instance in your case is "instance per owning class", so, it has the same effect as "this" for synchronization.Hydrobomb
H
12

Think of your code as the below one:

class A {

public void methodA() {
    synchronized(this){        
      //method A body
    }
}

public void methodB() {
    synchronized(this){
      // method B body
    }
}

So, synchronized on method level simply means synchronized(this). if any thread runs a method of this class, it would obtain the lock before starting the execution and hold it until the execution of the method is finished.

But can I run methodB() on different thread while methodA() is still running? (same object)

Indeed, it is not possible!

Hence, multiple threads will not able to run any number of synchronized methods on the same object simultaneously.

Hurlbut answered 5/1, 2018 at 2:18 Comment(2)
what if I create Threads on two different objects of the same class? In this case If I call one method from one thread and other method from second thread won't they be executing simultaneously?Compander
They will because they are different objects. That is, if you want to prevent it, you can use static methods and synchronize the class or use a class variable object as a lock or make the class Singleton. @Yug SinghHurlbut
W
8

From oracle documentation link

Making methods synchronized has two effects:

First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads

This will answer your question: On same object, You can't call second synchronized method when first synchronized method execution is in progress.

Have a look at this documentation page to understand intrinsic locks and lock behavior.

Whore answered 21/2, 2016 at 10:6 Comment(0)
S
4

Just to all clarity, It’s possible that both static synchronized and non static synchronized method can run simultaneously or concurrently because one is having object level lock and other class level lock.

Secretariat answered 13/7, 2014 at 13:55 Comment(0)
M
4

The key idea with synchronizing which does not sink in easily is that it will have effect only if methods are called on the same object instance - it has already been highlighted in the answers and comments -

Below sample program is to clearly pinpoint the same -

public class Test {

public synchronized void methodA(String currentObjectName) throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA in");
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA out");
}

public synchronized void methodB(String currentObjectName)  throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB in");
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB out");
}

public static void main(String[] args){
    Test object1 = new Test();
    Test object2 = new Test();
    //passing object instances to the runnable to make calls later
    TestRunner runner = new TestRunner(object1,object2);
    // you need to start atleast two threads to properly see the behaviour
    Thread thread1 = new Thread(runner);
    thread1.start();
    Thread thread2 = new Thread(runner);
    thread2.start();
}
}

class TestRunner implements Runnable {
Test object1;
Test object2;

public TestRunner(Test h1,Test h2) {
    this.object1 = h1;
    this.object2 = h2;
}

@Override
public void run() {
    synchronizedEffectiveAsMethodsCalledOnSameObject(object1);
    //noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(object1,object2);
}

// this method calls the method A and B with same object instance object1 hence simultaneous NOT possible
private void synchronizedEffectiveAsMethodsCalledOnSameObject(Test object1) {
    try {
        object1.methodA("object1");
        object1.methodB("object1");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

// this method calls the method A and B with different object instances object1 and object2 hence simultaneous IS possible
private void noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(Test object1,Test object2) {
    try {
        object1.methodA("object1");
        object2.methodB("object2");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
}

Notice the difference in output of how simultaneous access is allowed as expected if methods are called on different object instances.

Ouput with noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects() commented -the output is in order methodA in > methodA Out .. methodB in > methodB Out Ouput with *noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects()* commented

and Ouput with synchronizedEffectiveAsMethodsCalledOnSameObject() commented - the output shows simultaneous access of methodA by Thread1 and Thread0 in highlighted section -

Ouput with *synchronizedEffectiveAsMethodsCalledOnSameObject()* commented

Increasing the number of threads will make it even more noticeable.

Macadamia answered 8/4, 2019 at 18:51 Comment(0)
S
2

You are synchronizing it on object not on class. So they cant run simultaneously on the same object

Sessions answered 15/3, 2013 at 17:37 Comment(0)
S
2

No it is not possible, if it were possible then both method could be updating same variable simultaneously which could easily corrupt the data.

Sash answered 14/1, 2019 at 22:44 Comment(0)
C
-1

Two different Threads executing a common synchronized method on the single object, since the object is same, when one thread uses it with synchronized method, it will have to verify the lock, if the lock is enabled, this thread will go to wait state, if lock is disabled then it can access the object, while it will access it will enable the lock and will release the lock only when it's execution is complete. when the another threads arrives, it will verify the lock, since it is enabled it will wait till the first thread completes his execution and releases the lock put on the object, once the lock is released the second thread will gain access to the object and it will enable the lock until it's execution. so the execution will not be not concurrent, both threads will execute one by one, when both the threads use the synchronized method on different objects, they will run concurrently.

Capitoline answered 7/2, 2017 at 19:51 Comment(1)
Please punctuate and capitalise this mess properly. There is no such word as 'varify'.Houseman
I
-1

Yes, they can run simultaneously both threads. If you create 2 objects of the class as each object contains only one lock and every synchronized method requires lock. So if you want to run simultaneously, create two objects and then try to run by using of those object reference.

Insanitary answered 23/5, 2019 at 10:42 Comment(1)
I'm pretty sure they meant if both methods are called on the same objectPapyrology

© 2022 - 2024 — McMap. All rights reserved.