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
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