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