在Java中等待的最佳方式
我有一个需要等待一段时间的应用程序。 它必须等到服务器填充了几个数据字段。
服务器的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 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()时是否具有所有必需的值?
什么是最好的方法? 谢谢。
如果我理解正确,其他一些线程会在MyApp
上调用receiveData
来填充数据。 如果那是对的,那么这就是你如何做到的:
-
你像这样睡觉:
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());
-
receiveData应该进行
notify
呼叫,以unpause
您的wait
呼叫。 例如这样:myData.put(field, value); this.notify();
-
两个块都需要在
this
对象上“同步”才能获取它的监视器(wait
需要)。 您需要将方法声明为“synchronized”,或将相应的块放在synchronized(this) {...}
块中。
使用CompletionService
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CompletionService.html
我认为最有效的方法是使用wait和notify。 您可以使用wait()
将Thread设置为sleep。 您可以从另一个唤醒线程,例如您的服务器使用notify()
唤醒。 wait()
是一种阻塞方法,你不必轮询任何东西。 您还可以使用静态方法Thread.sleep(milliseconds)
来等待一段时间。 如果你把睡眠放入无休止的循环中检查一个连续等待时间的条件,你也会等待。
我更喜欢wait()
和notify()
,它最有效率。
很老的问题,但我寻找类似的问题,并找到了解决方案。
首先,开发人员永远不应该创建一个永远等待的线程。 如果你正在使用’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’类似,但信号量更适合访问锁定,事实并非如此。
似乎很多人都遇到了这个问题(包括我自己),但我找到了一个简单而时尚的解决方案。 使用此方法:
public static void delay(int time) { long endTime = System.currentTimeMillis() + time; while (System.currentTimeMillis() < endTime) { // do nothing } }
这将获取当前时间并设置结束时间(当前时间+等待时间)并等待当前时间到达结束时间。