在Java中等待的最佳方式

5
我是一位有用的助手,为您翻译如下内容:

我有一个应用程序需要等待某个未知的时间。它必须等到服务器填充完几个数据字段。

服务器的API提供了一种请求数据的方法,非常简单...

服务器的API还提供了一种逐个返回我的数据的方式。但它没有告诉我所有字段何时全部填充完成。

最有效的等待服务器处理完我的请求的方法是什么?以下是一些伪代码:

public class ServerRequestMethods {
    public void requestData();
}

public interface ServerDeliveryMethods {
    public void receiveData(String field, int value);
}

public class MyApp extends ServerRequestMethods implements ServerDeliveryMethods {
    //store data fields and their respective values
    public Hashtable<String, Integer> myData;    

    //implement required ServerDeliveryMethods
    public void receiveData(String field, int value) {
        myData.put(field, value);    
    }

    public static void main(String[] args) {
        this.requestData();

        // Now I have to wait for all of the fields to be populated,
        // so that I can decide what to do next.

        decideWhatToDoNext();
        doIt();
    }
}

我必须等到服务器完成填充我的数据字段,但服务器不会告诉我请求何时完成。因此,我必须不断检查我的请求是否已完成处理。最有效的方法是什么?
使用wait()和notify(),并使用一个方法来保护while循环,每次被notify()唤醒时检查是否已经拥有所有所需的值?
使用Observer和Observable,使用一个方法,在每次调用Observer.Update()时检查是否已经拥有所有所需的值?
哪种方法最好?谢谢。

服务器的API还提供了一种逐个字段接收我的数据的方式。这是如何工作的?调用是否等待特定字段被填充,还是立即返回,带或不带字段数据? - forty-two
@forty-two 为了接收消息,服务器要求我在伪代码中实现“ServerDeliveryMethods”接口。因此,当服务器向我发送数据时,它会调用这个方法,并将数据放入参数中。 - rallison
问题是 - 您的客户端应用程序认为什么是“完成”的?无论如何,您可能需要一个单独的线程与服务器通信,并且在主线程中等待的信号量(概念,而不是类),以保护 decideWhatToDoNext() 方法。 - Perception
@Perception 当Hashtable myData中的所有字段都被填充时,我的客户端应用程序就“完成”了。因此,我事先不知道服务器发送所有60个字段的值需要多长时间。 - rallison
5个回答

5

如果我理解得没错,其他 线程 调用你的 MyApp 上的 receiveData 来填充数据。如果是这样的话,那么以下就是你需要做的:

  1. You sleep like this:

    do {
        this.wait(someSmallTime); //We are aquiring a monitor on "this" object, so it would require a notification. You should put some time (like 100msec maybe) to prevent very rare but still possible deadlock, when notification came before this.wait was called.
    } while (!allFieldsAreFilled());
    
  2. receiveData should make a notify call, to unpause that wait call of yours. For example like this:

    myData.put(field, value);   
    this.notify();
    
  3. Both blocks will need to be "synchronized" on this object to be able to aquire it's monitor (that's needed for wait). You need to either declare the methods as "synchronized", or put the respective blocks inside synchronized(this) {...} block.


服务器调用receiveData方法,逐个将字段及其对应的值发送回给我。因此,有大约60个字段,因此服务器会调用此方法60次。所以我想这就是您所说的,因为服务器正在使用Java Socket,我猜这就像“其他一些线程”一样。是吗? - rallison
基本上,服务器没有简单地“调用receiveData”的方法。我猜你正在使用某种框架来完成这个任务。该框架接受服务器数据并调用你的方法。无论如何,这并不会改变什么。根据你的描述,你确实有两个单独的线程,因此这种方法是“等待”数据的最简单方式。 - bezmax
我在简化问题时省略了一些细节,但我明白您的意思。从技术上讲,ServerRequestMethods也提供了一个构造函数,它以ServerDeliveryMethods作为其参数。然后在MyApp构造函数中,我初始化了一个实例变量:myServerRequestMethodsInstance = new ServerRequestMethods(this)。然后在main函数中,实际调用是myServerRequestMethodsInstance.requestData()。因此,请求/接收类是相互关联的,服务器确实只是调用receiveData,尽管我不确定细节。但我认为这仍然没有改变什么。谢谢! - rallison
没问题。只是顺便提一下:您可以通过检查if (myData.size() >= 60)来优化代码,而不是检查所有60个字段是否为null。 - bezmax


1
我认为最有效的方法是使用wait和notify。你可以使用wait()将线程设置为休眠状态。你可以从另一个线程,例如你的服务器,使用notify()来唤醒该线程。wait()是一种阻塞方法,无需轮询任何内容。你也可以使用静态方法Thread.sleep(milliseconds)进行等待。如果你将sleep放入一个无限while循环中,并使用不断等待的时间检查条件,那么你将等待下去。
我更喜欢wait()和notify(),因为它是最高效的。

1

这是一个比较老的问题,但我搜索了类似的问题并找到了解决方法。
首先,开发人员不应该创建永远等待的线程。如果使用while循环,确实需要创建“退出条件”。此外,等待“InterruptedException”是棘手的。如果另一个线程没有调用yourThread.interrupt(),则会一直等待,直到程序真正结束。 我使用了java.util.concurrent.CountDownLatch,简而言之:

/*as field*/
CountDownLatch semaphore = new CountDownLatch(1);

/*waiting code*/
boolean timeout = !semaphore.await(10, TimeUnit.SECONDS);

/*releasing code*/
semaphore.countDown();

因此,“等待代码”线程将等待直到另一个线程调用“释放代码”或超时。如果您想等待10个字段被填充,请使用“new CountDownLatch(10)”。对于“java.util.concurrent.Semaphore”,原理类似,但信号量更适合访问锁定,而这不是您的情况。

-4

看起来许多人都遇到了这个问题(我也有),但是我已经找到了一个简单而流畅的解决方案。使用这个方法:

public static void delay(int time) {
    long endTime = System.currentTimeMillis() + time;
    while (System.currentTimeMillis() < endTime) 
    {
        // do nothing
    }
}

这段代码获取当前时间并设置一个结束时间(当前时间加上等待的时间),然后等待直到当前时间达到结束时间。

2
那是一个非常低效的解决方案,所以不要这样做。 - gyurix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接