Search code examples
javajava-threadsandroid-threadandroid-threading

Call a synchronized method with a new thread in a synchronized method


We have a task to perform, dummyMethod.

private synchronized void dummyMethod(){
    Log.d("debug", "do nothing in dummyMethod()")
}

We run that task several times.

private synchronized void fooMethod() throws InterruptedException{
    
    for (int i = 0; i < 10; i++){
        dummyMethod();
    }
   
   Thread.sleep(10000)
   Log.d("debug", "fooMethod() finished")
}

With the above code synchronized dummyMethod() is executed 10 times immediately.

However, with the following code, dummyMethod() is called only once immediately, and only after fooMethod() is finished did it get finished and executed 9 more times.

private synchronized void fooMethod() throws InterruptedException{
    
 new Thread(()->{
    for (int i = 0; i < 10; i++){
        dummyMethod();
    }
 }).start();
   
   Thread.sleep(10000)
   Log.d("debug", "fooMethod() finished")
}

In this case, logcat shows:

Long monitor contention with owner main (18077) at void ...fooMethod()(MainActivity.java:1106) waiters=0 in void ...MainActivity.dummyMethod() for 10.001s

I thought it would not block with a new thread in the latter case. Could anyone shed some light on this? How can a synchronized method run another synchronized method multiple times asynchronously in a new thread?


Solution

  • From my comment -

    From this Baeldung article: all synchronized blocks of the same object can have only one thread executing them at the same time

    So the current thread is already in a synchronized method, and the new thread cannot immediately execute dummyMethod() since it's the same object.

    Slight mod to the original code, showing use of a new instance does allow the new Thread to immediately run dummyMethod():

    package sandbox;
    
    public class SyncTest {
    
        public static void main(String[] args) throws InterruptedException {
            var test = new SyncTest();
            test.fooMethod();
        }
    
        private synchronized void dummyMethod() {
            System.out.println("do nothing in dummyMethod()");
        }
    
        private synchronized void fooMethod() throws InterruptedException {
            var t = new SyncTest(); // new instance will have its own monitor
            new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    t.dummyMethod();
                }
            }).start();
    
            Thread.sleep(10000);
            System.out.println("fooMethod() finished");
        }
    }