2

Suppose that a token machine can only issue one token at a time. The rule is that one token must be consumed before another one can be created.

class TokenMachine {
    private int tokenID;
    private boolean tokenExists = false;
    public synchronized void createToken(int coup){
      ...
    }
    public synchronized int consumeToken(){
      ...
    }
}

public synchronized void createToken(int coup) {
    while(tokenExists) { //can I change 'while' to 'if'?
        wait(); //in a try-catch block
    }
    this.tokenID = coup;
    tokenExists = true;
    notify();
}

public synchronized int consumeToken() {
    while(!tokenExists) { //can I change 'while' to 'if'?
        wait(); //in a try-catch block
    }
    tokenExists = false;
    notify();
    return tokenID;
}

My question is that can I change the 'while' expression in previous code to 'if' instead without vandalize the rule? Many thanks.

Thanks guys for answering my question, I checked a lot online, find the following info are helpful: A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops.

Apparently, the spurious wakeup is an issue (I doubt that it is a well known issue) that intermediate to expert developers know it can happen but it just has been clarified in JLS third edition which has been revised as part of JDK 5 development. The javadoc of wait method in JDK 5 has also been updated

4

2 回答 2

4

您需要使用while以避免在Spurious wake ups的情况下唤醒线程。在虚假唤醒的情况下,可以唤醒线程而不notify()被调用。while只有当它是真正的notify调用而不是虚假的重新激活时,循环才会重新检查条件并继续。

于 2013-10-09T09:38:29.527 回答
0
class TokenMachine {
  ArrayBlockingQueue<Integer> q=new ArrayBlockingQueue<Integer>(1);

  public synchronized void createToken(int coup){
    q.put(coup);
  }

  public synchronized int consumeToken(){
    return q.get();
  }
}
于 2013-10-09T11:21:40.167 回答