2

I am understanding wait() in Java in regards to multithreaded, and as per the documentation, wait() should always be in a loop.

I have difficult in understanding what is the condition we have to give in the loop. Typically, I have seen:

synchornized(obj) {
    while(some_condition) {
         obj.wait();
    }
    // some other code
}

I am having difficulty in understanding the "condition" which is used in the loop within which we are keeping wait().

I tried to implement a scenario in which I created two different threads (two different classes implementing Runnable interface), for printing Odd and Even numbers, like: 1 ,2 ,3,4,5,6...

As this is inter-thread communication and we need synchronization, I am having difficulty in relating what is the condition on which I have to keep wait() in loop for these two different threads.

Any clues as to how to decipher this (the condition we keep in loop) greatly appreciated.

CuriousMind
  • 8,301
  • 22
  • 65
  • 134
  • Is there any reason why thread that acquires the synchronized method "lock" might not be able to proceed and wants to give the key away temporarily to another thread that might change something so the thread giving the key away will be able to proceed? If yes - here's your condition. – zubergu May 10 '15 at 19:20
  • Yes. Imagine first the thread which prints the Odd number, prints 1; then this thread should wait till the other thread prints even number, 2 so on. Because they have to run : odd, even, odd , even, odd, even.... – CuriousMind May 10 '15 at 19:23
  • so here's your condition: was the last number printed an odd number? boolean last_printed_odd maybe? so you check in thread printing only even numbers and wait until this boolean is set to true. Which can be done only in thread printing odd numbers. So when thread printing even numbers gets processor time first and acquires the method, it's still possible to pass it to the even printing thread. – zubergu May 10 '15 at 19:25
  • http://stackoverflow.com/questions/1038007/why-should-wait-always-be-called-inside-a-loop – Sotirios Delimanolis May 10 '15 at 19:25

2 Answers2

1

The looping condition should check whether the execution(threads of the current class) need to be temporarily paused.

Taking an example of famous producer-consumer problem, where in the producer will somehow looks like

synchronized(mySharedObj)
{
while(mySharedObj.length==maxSize)
{
 mySharedObj.wait();
}
}

If there are n number of Producer Threads on mySharedObj, all will be waiting when the shared resource(mySharedObj) has reached its limit.

Sashi Kant
  • 13,277
  • 9
  • 44
  • 71
1

Here, maybe this few lines will push you in the right direction, as a follow up to my previous comments.

class LastPrintedMonitor {
    public boolean wasLastEven = false;

}

class PrinterOdd implements Runnable {

    LastPrintedMonitor monitor;

    public PrinterOdd(LastPrintedMonitor monitor) {
        this.monitor = monitor;
    }

    @Override
    public void run() {
        for (int i = 2; i < 40; i += 2) {
            synchronized (monitor) {
                while (!monitor.wasLastEven) {
                    try {
                        monitor.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                System.out.println(i);
                monitor.wasLastEven = false;
                monitor.notifyAll();
            }
        }

    }

}

class PrinterEven implements Runnable {

    LastPrintedMonitor monitor;

    public PrinterEven(LastPrintedMonitor monitor) {
        this.monitor = monitor;
    }

    @Override
    public void run() {
        for (int i = 1; i < 40; i += 2) {
            synchronized (monitor) {
                while (monitor.wasLastEven) {
                    try {
                        monitor.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                System.out.println(i);
                monitor.wasLastEven = true;
                monitor.notifyAll();
            }
        }

    }

}

public class EvenOddPrinterDemo {

    public static void main(String[] args) {
        LastPrintedMonitor monitor = new LastPrintedMonitor();

        Thread odd = new Thread(new PrinterOdd(monitor));
        Thread even = new Thread(new PrinterEven(monitor));

        odd.start();
        even.start();

        try {
            odd.join();
            even.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Done!");

    }

}

You mentioned two classes so their synchronized methods will not be synchronized to each other. That's why we synchronized on monitor, as there has to be something that those two objects share to make them "hear" each other.

zubergu
  • 3,646
  • 3
  • 25
  • 38
  • Amazing! I was doing a similar approach, however i kept the entire logic in infinite loop (for these two different threads). I had difficulty in "guessing" what the condition should be. FYI, here is my question in regards to that ---> http://stackoverflow.com/questions/30141414/program-gets-halted-wait-and-notify – CuriousMind May 10 '15 at 19:55