I have some code like this:
public class HelloWorld {
public static void main(String[] args){
ThreadB b = new ThreadB();
b.start();
Runnable a = new Runnable(){
public void run(){
System.out.println(Thread.currentThread().getId());
synchronized(b){
try{
System.out.println("Waiting for b to complete...");
b.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("Total is: " + b.total);
}
}
};
(new Thread(a)).start();
synchronized(b){
System.out.println(Thread.currentThread().getId());
try{
System.out.println("Waiting for b to complete...");
b.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("Total is: " + b.total);
}
}
}
Class ThreadB:
class ThreadB extends Thread{
int total;
@Override
public void run(){
synchronized(this){
for(int i=0; i<100 ; i++){
total += i;
}
System.out.println("Total is: " + total);
notify();
}
}
}
Basically, I have two threads which lock on the Threadb object b. When I run the code, I see:
1
Waiting for b to complete...
22
Waiting for b to complete...
Here, the numbers are the thread ids, so clearly, they are different threads. Also, the object they are locking on is the same(b). However, both are able to enter the synchronized block and wait on the object.
How's it possible?
Moreover, if I insert 2 other lines in the threadB.run() method:
class ThreadB extends Thread{
int total;
@Override
public void run(){
synchronized(this){
for(int i=0; i<100 ; i++){
total += i;
}
System.out.println("Total is: " + total);
notify();
}
}
}
The 2 threads run to completion:
Total is: 4950
22
1
Waiting for b to complete...
Waiting for b to complete...
Total is: 4950
Total is: 4950
It seems that in the older definition of ThreadB.run(), a notify signal was missed by the waiting threads, so they wait indefinitely. Is it correct?
Also, if a thread exits without calling notify(), the lock gets released intrinsically (equivalent to notifyAll()). Is that right?