[Java notify()在wait()之前被调用

问题描述 投票:5回答:5

难道另一个线程中的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。

我们如何预防呢?

java multithreading wait notify
5个回答
7
投票

5
投票
听起来只有在某些条件成立的情况下,您想要的是等待。例如:

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


1
投票
Java的Future接口是为只能在以后才能到达的结果而设计的,并且FutureTask类实现了此接口。

使第一个线程获得对Future的访问权,并让第二个线程运行FutureTask,所有这些工作都将为您处理。您还可以免费获得超时支持。


0
投票
class EMU{ ResultVar RV; Address my_address; volatile boolean condition = true; ResultVar findValue(String key){ String tgt = findTarget(key); sendRequest(tgt, key); synchronized(RV){ while(condition == true) { 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){ condition = false; RV.notify(); } } } };

0
投票
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. 1秒后,主线程正在加入RV同步。
  2. 该锁将得到通知,并使自定义线程继续工作。
  3. 自定义线程离开synchronized(lock)块。
  4. 主线程将RV等待锁定。
  5. 自定义线程通知RV锁继续。
  • 程序结束。
  • © www.soinside.com 2019 - 2024. All rights reserved.