Home > Back-end >  Need to clear my mind on methods wait() e notify();
Need to clear my mind on methods wait() e notify();

Time:12-14

class Q {
    int n;
    boolean valueSet = false;

    synchronized int get() {
        while (!valueSet)
            try {
                wait();
            } catch (Exception e) {
            }
        ;


        System.out.println("Pego : "   n);
        valueSet = false;
        notify();

        return n;
    }

    synchronized void put(int n) {
        while (valueSet)
            try {
                wait();
            } catch (Exception e) {
            }
        ;

        this.n = n;
        valueSet = true;
        System.out.println("Inserido : "   n);
        notify();
    }

}

class Producer2 implements Runnable {
    Q q;

    Producer2(Q q) {
        this.q = q;
        new Thread(this, "Geradora").start();
    }

    public void run() {
        int i = 0;
        while (true) {
            q.put(i  );
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {

                e.printStackTrace();
            }
        }
    }
}


class Consumer2 implements Runnable {
    Q q;

    Consumer2(Q q) {
        this.q = q;


        new Thread(this, "Consumidora").start();
    }

    public void run() {
        while (true) {
            q.get();
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class PCFixed {

    public static void main(String[] args) {
        Q q = new Q();
        new Producer2(q);
        new Consumer2(q);
    }
}

Text from the book: Inside get(), wait() is called. This suspends the execution till Producer notify... My question is, Once I instantiate Producer and Consumer, the execution reaches put, not get. So how come it calls get first and then call wait() inside get()?

CodePudding user response:

The system can only be in one of two states:

It is empty

valueSet is false, the put method will not even once enter that while loop and thus never invokes wait(), and the get method would wait().

It is full

valueSet is true, the get method will not even once enter that while loop and thus never invokes wait(), and the put method would wait().

Explanation

Because the get and put methods are synchronized, only one can be running (and note that wait() will open the gates and let other code run. It'll re-acquire the lock before wait() actually exits - for code to go on past a wait(), both notify() must be called, and whatever called it needs to get to the end of it synchronized block/method.

The code starts off in 'empty' mode.

It doesn't matter if you attempt to invoke put and get simultaneously; these methods are synchronized on the this reference so only one can actually run, the other would freeze until the lock is available. Thus, we have two options:

  • The put call wins. In this case, the put call will immediately set the value and not wait at all, sets the mode to 'full' (valueSet = true), does a useless notify() that has no effect but also does no harm, and ends. The get call was waiting to start and can now start. It will not wait at all (as it is in "full" mode; valueSet == true), gets the value and prints it, sets the mode back to empty, does another useless notify, and exits.

  • The get call wins. In this case, the get call will enter the while loop and waits. This releases the lock, which means the put call can now go. It will not wait at all (as the while loop's condition is false, which means it runs zero times), it sets a value, and notify() - that 'releases' the get() call which now merely waits for the lock to be available to continue. The put method ends, thus releasing the lock. The get call continues and fetches the value. It then does a useless notify, and exits as well.

  • Instead you attempt to run 2 put calls simultaneously. One wins and immediately sets as usual, then the other runs and will immediately enter wait mode and will be stuck there (as will any further put calls, they all run into the wait() call and wait there), until you call get() in some thread, this will get a value, set the thing to be in 'empty' mode, and notifies one arbitrary thread, thus unlocking it. It will put its value and set your object back to "full" mode and exit, leaving the other putters still waiting around. Another get call would immediately proceed, fetch it, notify another one of the waiting put calls, and so on.

CodePudding user response:

Because both Producer2 and Consumer2 create a new thread in their constructors.

So calling

new Producer2(q);

In the main method, doesn't stop the execution, it goes immediately to the next line which is

new Consumer2(q);

Which is where the call to q.get happens

  • Related