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 uselessnotify()
that has no effect but also does no harm, and ends. Theget
call was waiting to start and can now start. It will notwait
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, theget
call will enter the while loop and waits. This releases the lock, which means theput
call can now go. It will not wait at all (as thewhile
loop's condition is false, which means it runs zero times), it sets a value, andnotify()
- that 'releases' theget()
call which now merely waits for the lock to be available to continue. Theput
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 furtherput
calls, they all run into thewait()
call and wait there), until you callget()
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 waitingput
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