Best way to wait in Java

落爺英雄遲暮 提交于 2019-12-05 01:54:25

问题


I have an app that needs to wait for some unknown amount of time. It must wait until several data fields are finished being populated by a server.

The server's API provides me a way to request data, easy enough...

The server's API also provides a way to receive my data back, one field at a time. It does not tell me when all of the fields are finished being populated.

What is the most efficient way to wait until my request is finished being processed by the server? Here's some pseudocode:

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

I have to wait until the server is finished populating my data fields, and the server doesn't let me know when the request is complete. So I must keep checking whether or not my request has finished processing. What is the most efficient way to do this?

wait() and notify(), with a method guarding the while loop that checks if I have all of the required values yet every time I'm woken up by notify()?

Observer and Observable, with a method that checks if I have the all the required values yet every time my Observer.Update() is called?

What's the best approach? Thanks.


回答1:


If I understood you right, some other thread calls receiveData on your MyApp to fill the data. If that's right, then here's how you do it:

  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.




回答2:


Use a CompletionService

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CompletionService.html




回答3:


i think the most efficient method is with wait and notify. You can set a Thread into sleep with wait(). You can wake up the Thread from another one, e.g. your server with notify() to wake up. wait() is a blocking method, you dont have to poll anything. You can also use the static method Thread.sleep(milliseconds) to wait for a time. If you put sleep into a endless while loop checking for a condition with a continusly wait time, youll wait also.

I prefer wait() and notify(), its most efficient at all.




回答4:


Pretty old question, but I looked for similar problem and found a solution.
At first, developer should never create a thread that will wait forever. You really have to create 'exit condition' if you are using 'while' cycle. Also, waiting for 'InterruptedException' is tricky. If another thread doesn't call yourThread.interrupt() you'll wait until program truly ends. I used java.util.concurrent.CountDownLatch so in short:

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

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

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

As result, 'waiting code' thread will wait until some another Thread calls 'releasing code' or will "timeout". If you want to wait for 10 fields to be populated, then use 'new CountDownLatch(10)'.
This principle is similar for 'java.util.concurrent.Semaphore' but semaphore is better for access locking and that isn't your case, indeed.




回答5:


It seems like many people have been having trouble with this (myself included) but I have found an easy and sleek solution. Use this method:

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

This gets the current time and sets an end time (current time + time to wait) and waits until the current time hits the end time.



来源:https://stackoverflow.com/questions/9411950/best-way-to-wait-in-java

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!