在等待()之前调用Java notify()

在等待()之前调用Java notify(),java,multithreading,wait,notify,Java,Multithreading,Wait,Notify,另一个线程中的notify()不可能在一个线程中的wait()之前被调用吗? 这件事发生在我身上 客户端从目标请求一个值,并等待结果变量RV。 如果目标是客户机本身,我将使用正确的结果更新RV,并在另一个线程中对RV调用notify() class EMU { ResultVar RV; Address my_address; ResultVar findValue(String key) { String tgt = findTarget(key); sendR

另一个线程中的notify()不可能在一个线程中的wait()之前被调用吗? 这件事发生在我身上

客户端从目标请求一个值,并等待结果变量RV。 如果目标是客户机本身,我将使用正确的结果更新RV,并在另一个线程中对RV调用notify()

class EMU {

  ResultVar RV;
  Address my_address;

  ResultVar findValue(String key) {
    String tgt = findTarget(key);
    sendRequest(tgt, key);
    synchronized(RV) {
      RV.wait();
    }

    return RV;
  }

  Runnable Server = new Runnable() {
    public void run() {
      //code to receive connections. Assume object of type Request is read from the stream.
      Request r = (Request) ois.readObject();
      if(r.requesterAddr.compareTo(my_address) == 0) {
        String val = findVal(key);
        RV.putVal(val);
        synchronized(RV){
          RV.notify();
        }
      }
    }
  };
}
问题在于,在请求者自己完成所有“联网”(上例中为sendReqest)之前,结果会在结果变量中更新。当请求者线程现在调用wait()时,程序不会继续,因为已经调用了notify


我们如何防止它呢?

如果在等待之前(在循环中)检查一些标志,请参阅教程:

对于没有被另一个线程
等待
的对象,没有任何东西可以阻止您调用
notify

class EMU {

  ResultVar RV;
  Address my_address;

  ResultVar findValue(String key) {
    String tgt = findTarget(key);
    sendRequest(tgt, key);
    synchronized(RV) {
      RV.wait();
    }

    return RV;
  }

  Runnable Server = new Runnable() {
    public void run() {
      //code to receive connections. Assume object of type Request is read from the stream.
      Request r = (Request) ois.readObject();
      if(r.requesterAddr.compareTo(my_address) == 0) {
        String val = findVal(key);
        RV.putVal(val);
        synchronized(RV){
          RV.notify();
        }
      }
    }
  };
}
听起来,只有在某些条件成立时,您才需要等待。例如:

synchronized (results) {
    while (!results.hasResults()) {
        // no results yet; wait for them
        try {
            results.wait();
        } catch (InterruptedException ie) { /* ignore */ }
    }
}

我强烈建议不要重新发明轮子

Java的接口是为以后可能到达的结果而设计的,类实现了这个接口


让第一个线程访问未来,让第二个线程运行FutureTask,所有这些都会为您处理。您还可以免费获得超时支持。

在转到wait()之前使用一些条件,并确保该条件是线程安全的:)


首先让我将代码分解为可复制的最小值:

public static void main(String[] args) throws Exception {
    Object RV = new Object();
    new Thread() {
        @Override
        public void run() {
            synchronized (RV) {
                RV.notify();
            }
        }
    }.start();
    Thread.sleep(1_000);
    synchronized (RV) {
        RV.wait();
    }
}
这种方法理论上永远不会结束,程序也永远不会退出。如果这是一个僵局,这将是一个争议

我的解决方案是创建第二个锁:

public static void main(String[] args) throws Exception {
    Object RV = new Object();
    Object lock = new Object();
    new Thread() {
        @Override
        public void run() {
            synchronized (lock) {
                lock.wait();
            }
            synchronized (RV) {
                RV.notify();
            }
        }
    }.start();
    Thread.sleep(1_000);
    synchronized (RV) {
        synchronized (lock) {
            lock.notify();
        }
        RV.wait();
    }
}
让我们检查主线程等待一秒钟时线程正在执行的操作:

  • 自定义线程将首先加入
    synchronized(lock)
  • 然后锁将导致自定义线程等待
  • 1秒后,主线程连接RV同步
  • 锁会得到通知,并使自定义线程继续工作
  • 自定义线程将保持
    同步(锁定)
  • 主螺纹将处于RV等待锁定状态
  • 自定义线程通知RV锁继续

  • 程序结束。

    如果目标是客户机本身
    这是什么意思?你能放一些代码样本吗?@shishir garg你能在没有看到代码的情况下粘贴一些代码吗?很难回答-2条评论:a)通常使用notifyAll比notify更好,除非您知道自己在做什么b)使用wait和notify可能容易出错,并且您应该使用更高级别的并发API,除非您需要非常具体的东西。