Search code examples
javamultithreadingsynchronized

Why does another thread get access to blocked object while synchronized section has not completed?


The message "main Thread" is printed before message "new Thread" though method with message "new Thread" is in syncronized section by object which include print* methods.

    Test test = new Test();
    new Thread(() -> {
        try {
            synchronized (test) {
                Thread.sleep(5000);
                test.printMessage();
            }
        } catch (InterruptedException e) {}
    }).start();
    Thread.sleep(1000);
    test.printAnotherMessage();
}

public void printMessage() {
    System.out.println("new Thread");
}

public void printAnotherMessage() {
    System.out.println("main Thread");
}

}


Solution

  • There is no synchronisation on test.printAnotherMessage(); so it will be executed first assuming the timing is right. 4 seconds is a lot and should be enough.

    synchronized (test) {
        test.printAnotherMessage();
    }
    

    Thread.sleep is rarely a good option, though. A more proper way would be

    Test test = new Test();
    
    new Thread(() -> {
        synchronized (test) {
            test.printMessage();
            test.notify();
        }
    }).start();
    
    synchronized (test) {
        test.wait();
        test.printAnotherMessage();
    }
    

    I am playing a dangerous game here since I am assuming the main thread will enter the synchronized block and execute wait() before another thread is created and it enters its synchronized block. It's reasonable since creating a thread will take some time.

    Test test = new Test();
    new Thread(() -> {
        try {
            // a lot of time to let the main thread execute wait()
            Thread.sleep(500); 
    
            synchronized (test) {
                test.printMessage();
                test.notify();
            }
        } catch (InterruptedException e) {}
    }).start();
    
    synchronized (test) {
        test.wait();
        test.printAnotherMessage();
    }