Rahul Shivsharan
Rahul Shivsharan

Reputation: 2561

wait and notify explanation required

I am reading and trying to understand the wait and notify mechanism in the thread. For that i need to clear my concepts, hence to just make sure about my concept i am asking question on the examples tried, as follows

Please follow the code snippet,

class CodeOne implements Runnable{

    @Override
    public void run(){
        try{
            synchronized(this){
                for(int i=1;i<=5;i++){
                    System.out.println(Thread.currentThread().getName()+" : "+i);
                    Thread.sleep(500);
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

public class ThreadPractiseOne{ 

    public static void testOne() throws Exception{
        CodeOne code = new CodeOne();
        Thread t1 = new Thread(code,"THREAD-ONE");
        Thread t2 = new Thread(code,"THREAD-TWO");
        t1.start();
        t2.start();
    }

    public static void main(String[] args){
        try{
            testOne();
        }catch(Exception e){

        }
    }
}   

From the above code we can see the sunchronized block uses 'this' as argument. the purpose of it is that, the threads created in the main method acquire lock on the object CodeOne and hence only one thread is able to access it.

Is my above understanding correct ?

if yes,

than i want to ask one more question on the basis of the code written as follows,

public class MyThread extends Thread{

    public MyThread(String name){
        this.setName(name);
    }

    public int total;

    @Override
    public void run(){
        try{
            synchronized(this){
                System.out.print(" ");
                for(int num=1; num <= 3; num++){
                    total += num;
                    System.out.print("..");
                    Thread.sleep(1000);
                }
                System.out.println("\n");
                notify();
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

public class MainThread {

    public static void main(String [] args){
        MyThread t1 = new MyThread("ONE");

        try{
            t1.start();
            synchronized(t1){
                System.out.println(" Waiting for Thread ONE to complete ");
                t1.wait();
            }

            System.out.println(" TOTAL is  "+t1.total);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

From the above code we can see here in the main method of class MainThread, i have used synchronized block but the argument passed i t1 i.e the thread instance.

is this mean that the main thread acquires a lock on 't1' ?

if yes why ?

and if i do

synchronized(new MainThread())

in the MainThread class, i get an exception

java.lang.IllegalMonitorStateException

why ?

by the way the output of the 2nd program is

Waiting for Thread ONE to complete 
 ......
 TOTAL is  6

Upvotes: 0

Views: 100

Answers (2)

Gray
Gray

Reputation: 116938

the threads created in the main method acquire lock on the object CodeOne and hence only one thread is able to access it.

Yes this is correct. It is very important to realize that they are locking on the same instance of CodeOne. Locks only work if multiple threads are synchronized on the same object instance.

is this mean that the main thread acquires a lock on 't1' ?

Yes. Both the main thread and the forked thread both are locking on the same Thread instance. As an aside it is considered a better pattern to define your class to implements Runnable instead of extending Thread. For example, other parts of the Thread code lock on the Thread instance. Since you are locking on it is as well this may cause some unintended consequences.

It is also important to realize that just calling notify(); is a bad pattern. You should explicitly say this.notify();. They do the same thing but it should have parity between synchronized (this) { ... this.notify(); }.

is this mean that the main thread acquires a lock on 't1' ?

Yes. The main thread is locking on t1 and inside of the thread it is locking on this. So they are locking on the same object instance. I'm not sure how to answer the "why" question.

java.lang.IllegalMonitorStateException

This happens when you are trying to do a wait() or notify() without being inside of a synchronized block. In your case if you say:

synchronized(new MainThread()) {
    ...
    notify();
}

Then you are synchronizing on one object and trying to notify on a different object that you don't have locked. The lock object is typically supposed to be a private final object instance shared by multiple threads. Doing something like synchronized (new ...) is really never a good pattern.

Upvotes: 1

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 280172

From the above code we can see the synchronized block uses 'this' as argument. the purpose of it is that, the threads created in the main method acquire lock on the object CodeOne and hence only one thread is able to access it.

Only one thread at a time is able to access code inside a synchronized block that is synchronized on that object.

is this mean that the main thread acquires a lock on 't1' ?

In this example, this and t1 happen to refer to the same MyThread object.

in the MainThread class, i get an exception

You will have to show us the code that actually causes this, but you can't call notify or wait on objects which you haven't synchronized on.

by the way the output of the 2nd program is

This depends on a race condition. It depends on which Thread acquires the lock on the MyThread object first. If it's the main thread, then that's the output you will get. If it's the other thread, those lines will be reversed.


I don't see a question on wait() and notify() so I'll just refer to Gray's answer, who has given a general explanation.


Finally, don't ever synchronized on Thread objects. They have different behavior than normal objects when the actual thread they are referring to comes to an end.

Upvotes: 1

Related Questions