有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程处理Java wait()方法的行为

假设令牌机一次只能发出一个令牌。规则是必须先使用一个令牌,然后才能创建另一个令牌

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;
}

我的问题是,我可以在不破坏规则的情况下,将以前代码中的“while”表达式改为“if”吗?非常感谢

感谢各位回答我的问题,我在网上查了很多,发现以下信息很有帮助: 线程也可以在不被通知、中断或超时的情况下唤醒,即所谓的虚假唤醒。虽然这种情况在实践中很少发生,但应用程序必须通过测试本应导致线程被唤醒的条件来防范这种情况,并在条件不满足时继续等待。换句话说,等待应该总是在循环中发生

显然,虚假唤醒是一个问题(我怀疑这是一个众所周知的问题),中级到专家级的开发人员知道它可能发生,但它刚刚在JLS第三版中得到澄清,该版本已作为JDK 5开发的一部分进行了修订。jdk5中wait方法的javadoc也已经更新


共 (2) 个答案

  1. # 1 楼答案

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

  2. # 2 楼答案

    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();
      }
    }