Synchronized block in the main method

心不动则不痛 提交于 2019-12-06 14:12:20

问题


In the below code about the synchronisation between threads, according to the output generated why is the control being transferred to the execution of the new thread despite the lock being acquired for the same object "dt" in the main method ?

public class DemoThread extends Thread {

public DemoThread() {
}

public void run() {
    int i=0;
    synchronized(this) {
        while(++i<=5) {
            sum=i;
            try{
                sleep(1000);
                System.out.println("Woke up from sleep");
               if(i>=2) this.notify();
            }catch(InterruptedException ie) {
                ie.printStackTrace();
                System.exit(1);
            }
        }
    }
}
private static int sum;    

public static void main(String... args) {

    DemoThread dt = new DemoThread();
    dt.start();

    synchronized(dt) {
        try{
            System.out.println("main here");
            dt.wait();
            System.out.println("main here again");
            System.out.println("sum = " + sum);
        }catch(InterruptedException ie){
            ie.printStackTrace();
            System.exit(1);
        }
    }        
}
}

Output :

main here
Woke up from sleep
Woke up from sleep
Woke up from sleep
Woke up from sleep
Woke up from sleep
main here again
sum = 5

EDIT: I think I was able to find one of the possible flow of the code to explain the output:

1.Main thread enters in the Sync block in the main method.

2.call to the wait is made. Lock released on the dt object

3.New thread enters the while loop as it has the lock on the object dt

4.Thread.Sleep is executed and it doesn't release the lock

5.notify call is made but doesnot wakr the main thread(?)

6.New and the main thread finish the execution

Please correct me if I am wrong


回答1:


You are close :

1.Main thread enters in the Sync block in the main method.

2.call to the wait is made. Lock released on the dt object

3.New thread enters the while loop as it has the lock on the object dt

4.Thread.Sleep is executed and it doesn't release the lock

5.notify call is made but doesnot wake the main thread(?)

6.New and the main thread finish the execution

Until the step 4, it is correct.

Here is what it happens at the step 5 :

notify() is invoked and the main() thread is so notified.
But it will not have a chance to run again right now.
Why ? Because the DemoThread thread doesn't release the lock.

The notify() method is indeed executed in a loop inside a synchronized statement.

synchronized (this) {
    while (++i <= 5) {
        sum = i;
        try {
            sleep(1000);
            System.out.println("Woke up from sleep");
            if (i >= 2) {
                notify();
            }

        } catch (InterruptedException ie) {
            ie.printStackTrace();
            System.exit(1);
        }
    }

And according to Object.notify() javadoc :

The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.

So the main() thread could run only as the run() method DemoThread is terminated.

To let the main() thread to run again, you could reverse in the DemonThread run() method, the synchronized statement and the while statement.
You should also make this thread sleep a little bit to let the main() thread to run again.

public void run() {
    int i = 0;

    while (++i <= 5) {
        // let a chance for other threads
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (this) {
            sum = i;
            try {
                sleep(1000);
                System.out.println("Woke up from sleep");
                if (i >= 2) {
                    notify();                   
                }

            } catch (InterruptedException ie) {
                ie.printStackTrace();
                System.exit(1);
            }
        }
    }
}

Now as i >= 2, as previously, other threads are notified but as the thread leaves the lock as it loops on the while and then sleep 100 ms, the main() thread can run again.

Here is the output :

main here

Woke up from sleep

Woke up from sleep

main here again

sum = 2

Woke up from sleep

Woke up from sleep

Woke up from sleep




回答2:


The synchronized keyword isn't used to control the execution of a thread, it's used to ensure that only one thread can enter a block of code at any one time. Typically whole methods can be synchronized or code between {}.

You can also synchronize an object that will be shared between two or more threads, typically some data structure that will be updated by the threads and you need to ensure that the state is consistent and not partially updated.

In your example there is no contention on the synchronize, if you extedt the sample to introduce some object and multiple threads trying to write and read from this object you will get a better understanding.



来源:https://stackoverflow.com/questions/48240147/synchronized-block-in-the-main-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!