Question

I pasted the code below. That is commented enough. Clear about wait(). When comes here it jumps to another block. That part i am oaky. My doubt is Why we are using notify and notifyAll(). If you remove these two from below code, it works fine.

class Reader extends Thread{
    Calculator c;
    //here we didn't write no-arg constructor.  Note this.
    // one - arg constructor.
    public Reader(Calculator calc){
        c = calc;
    }
    public void run(){
        synchronized(c){
        // 2. Acquiring the object lock and executes this code of block.
            try{
                System.out.println("Waiting for calculation...");
                c.wait();
                // 3.  Release the object lock and moves to the second synchronize block below
                // 6. Later the object get the lock here and moves on.
            }catch(InterruptedException e){
            }
            System.out.println("Total is: "+c.total);
        }
    }
    public static void main(String[] args){
        //Instantiating new with no-arg.  One more doubt,  How this work without no-arg constructor above.  Please explain.
        Calculator calculator = new Calculator();
        //Instantiating new with one-arg
        new Reader(calculator).start();
        new Reader(calculator).start();
        new Reader(calculator).start();
        // 1. Once you start here it will goto first synchronized code block above
        calculator.start();
    }
}

class Calculator extends Thread{
    int total;

    public void run(){
        synchronized(this){
        // 4. This block acquires that object lock and executes the code block below.

            for(int i=0;i<100;i++){
                total +=i;
            }
            // 5.  As per documentation,  If we give notify() it will release the object lock to only one thread object of its choice.
            //     If we use notifyAll(); it will release the object lock to all the three thread object.
            notify();
            // My doubt here is without using the notify or notifyAll it is working fine.
            // As per docs if we use notify() only one object should get the lock.  That is also not working here.
        }
    }
}
Was it helpful?

Solution

General comment: the javadoc of Object#wait states that

As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop.

So a waiting thread can wake up without being notified and your design should take that into account by waiting in a loop and checking for an exit condition (cf example in the javadoc).


In your case, however, the issue is slightly different. According to the Thread#join javadoc:

As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.

So when your Calculator finishes, it calls this.notifyAll() and wakes up all the waiting threads.


How to fix it?

You should use a separate lock object, similar to: private final Object lock = new Object(); in your Calculator and provide a getter for the Readers.

OTHER TIPS

There is no guarantee about the order in which the threads begin to run. If Calculator runs first then its notify will be lost and no one Reader will be notified.

Here is the corrected version of the above program which makes some sense to notify() and notifyAll(). Here i implemented Runnable instead of extending Threads. Thats the only change i did. Its working perfectly.

class Reader implements Runnable{
    Calculator c;
    public Reader(Calculator calc){
        c = calc;
    }
    public void run(){
        synchronized(c){
            try{
                System.out.println("Waiting for calculation...");
                c.wait();

            }catch(InterruptedException e){
            }
            System.out.println("Total is: "+c.total);
        }
    }
    public static void main(String[] args){

        Calculator calculator = new Calculator();

        Reader read = new Reader(calculator);

        Thread thr  = new Thread(read);
        Thread thr1 = new Thread(read);
        Thread thr2 = new Thread(read);

        thr.start();
        thr1.start();
        thr2.start();
        new Thread(calculator).start(); 
    }
}
class Calculator implements Runnable{
    int total;
    public void run(){
    System.out.println("Entered Calculator");
        synchronized(this){
            for(int i=0;i<20;i++){
                total +=i;
            }
                notifyAll();
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top