Here is my code for the problem which works fine, however, when I change the while statement right under synchronized statement, it seems any thread that get the lock after notifyall() just continue to run the code and causing odd method accept even number, even method accept odd number.
class ZeroEvenOdd {
private int n;
private AtomicInteger counter;
private AtomicInteger mode;
private Object lock;
public ZeroEvenOdd(int n) {
this.n = n;
this.counter = new AtomicInteger(0);
this.mode = new AtomicInteger(0);
this.lock = new Object();
}
public void zero(IntConsumer printNumber) throws InterruptedException {
while(counter.get() < n){
synchronized(lock){
// if I change this line to
// if(mode.get() == 1 || mode.get() == 3){lock.wait();}
// then everything goes wrong
while(mode.get() == 1 || mode.get() == 3){lock.wait();}
if(counter.get() < n){
printNumber.accept(0);}
mode.incrementAndGet();
lock.notifyAll();
}
}
}
public void even(IntConsumer printNumber) throws InterruptedException {
while(counter.get() < n){
synchronized(lock){
// if I change this line to
// if(mode.get() != 3){lock.wait();}
// then everything goes wrong
while(mode.get() != 3){lock.wait();}
if(counter.get() < n){
printNumber.accept(counter.incrementAndGet());}
mode.set(0);
lock.notifyAll();
}
}
}
public void odd(IntConsumer printNumber) throws InterruptedException {
while(counter.get() < n){
synchronized(lock){
// if I change this line to
// if(mode.get() != 1){lock.wait();}
// then everything goes wrong
while(mode.get() != 1){lock.wait();}
if(counter.get() < n){
printNumber.accept(counter.incrementAndGet());}
mode.incrementAndGet();
lock.notifyAll();
}
}
}
}
It seems to me that, when I use while, whichever thread got the lock after notifyAll will check the mode again, but when I change to if, it will not check mode and just continue from where it left.
I searched online, after notifyAll(), the next thread get the lock will continue from where it left, it wont revisit the code before wait().
But by using while here, it strangely check the mode variable again.
whileis a looping construct.It is not that the thread revisits the code before - it just loops again:
After the
wait()call finishes the loop condition is evaluated again in the same way thatloops for as long as
counter.get()returns a value less thann.The other approach (using if):
only calls
lock.wait();once ifmode.get()returns something else then3. Afterlock.wait();returns it just continues with the code after theifstatement, no matter whatmode.get()would return.