这是我解决问题的代码,工作正常,但是,当我在同步语句下更改 while 语句时,似乎任何在notifyall()之后获得锁的线程都会继续运行代码并导致奇数方法接受偶数,偶数方法接受奇数。
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();
}
}
}
}
在我看来,当我使用while时,无论哪个线程在notifyAll之后获得锁,都会再次检查模式,但是当我更改为if时,它不会检查模式,只是从离开的地方继续。
网上查了一下,notifyAll()之后,下一个获得锁的线程会从原来的地方继续,不会再去访问wait()之前的代码。
但是通过在这里使用 while ,它会奇怪地再次检查模式变量。
while
是一个循环结构。
线程并不是重新访问之前的代码 - 它只是再次循环:
while (mode.get() != 1) {
lock.wait();
}
wait()
调用完成后,循环条件将以与相同的方式再次评估
while (counter.get() < n) {
// some code here that might modify the value of the counter
}
只要 counter.get()
返回的值小于
n
,就会循环。
另一种方法(使用 if):
if (mode.get() != 3) {
lock.wait();
}
如果 lock.wait();
返回其他内容,然后
mode.get()
,仅调用
3
一次。 lock.wait();
返回后,它只会继续执行if
语句之后的代码,无论mode.get()
会返回什么。