睡觉并检查,直到情况成立

Java中是否有一个库可以执行以下操作? thread应重复sleep x毫秒,直到条件变为真或达到最大时间。

这种情况主要发生在测试等待某些条件变为真时。 条件受另一个thread影响。

[编辑]为了让它更清楚,我希望测试在失败前只等待X ms。 它不能永远等待条件成为现实。 我正在添加一个人为的例子。

 class StateHolder{ boolean active = false; StateHolder(){ new Thread(new Runnable(){ public void run(){ active = true; } }, "State-Changer").start() } boolean isActive(){ return active; } } class StateHolderTest{ @Test public void shouldTurnActive(){ StateHolder holder = new StateHolder(); assertTrue(holder.isActive); // i want this call not to fail } } 

编辑

大多数答案都集中在具有等待和通知或条件的低级API上(它们或多或少地以相同的方式工作):当您不习惯时,很难做到正确。 certificate:其中2个答案不正确使用等待。
java.util.concurrent为您提供了一个高级API,其中隐藏了所有这些复杂性。

恕我直言,当并发包中有一个实现相同的内置类时,没有必要使用wait / notify模式。


初始计数为1的CountDownLatch就是这样:

  • 当条件成立时,调用latch.countdown();
  • 在等待的线程中,使用: boolean ok = latch.await(1, TimeUnit.SECONDS);

举例:

 final CountDownLatch done = new CountDownLatch(1); new Thread(new Runnable() { @Override public void run() { longProcessing(); done.countDown(); } }).start(); //in your waiting thread: boolean processingCompleteWithin1Second = done.await(1, TimeUnit.SECONDS); 

注意:CountDownLatches是线程安全的。

你应该使用Condition

如果您希望除条件之外还有超时,请参阅await(long time, TimeUnit unit)

Awaitility提供简单而干净的解决方案:

await()。atMost(10,SECONDS).until(() – > condition());

我一直在寻找像Awaitility所提供的解决方案。 我想我在问题中选择了一个不正确的例子。 我的意思是,在您希望发生由第三方服务创建的异步事件并且客户端无法修改服务以提供通知的情况下。 一个更合理的例子是下面的例子。

 class ThirdPartyService { ThirdPartyService() { new Thread() { public void run() { ServerSocket serverSocket = new ServerSocket(300); Socket socket = serverSocket.accept(); // ... handle socket ... } }.start(); } } class ThirdPartyTest { @Before public void startThirdPartyService() { new ThirdPartyService(); } @Test public void assertThirdPartyServiceBecomesAvailableForService() { Client client = new Client(); Awaitility.await().atMost(50, SECONDS).untilCall(to(client).canConnectTo(300), equalTo(true)); } } class Client { public boolean canConnect(int port) { try { Socket socket = new Socket(port); return true; } catch (Exception e) { return false; } } } 

你不应该睡觉,检查,睡觉和检查。 您希望等待一个条件变量并让条件发生变化,并在执行某些操作时唤醒该线程。

看起来你要做的就是检查条件然后是否为假等待到超时。 然后,在另一个线程中,一旦操作完成,就通知notifyAll。

服务员

 synchronized(sharedObject){ if(conditionIsFalse){ sharedObject.wait(timeout); if(conditionIsFalse){ //check if this was woken up by a notify or something else //report some error } else{ //do stuff when true } } else{ //do stuff when true } } 

  synchronized(sharedObject){ //do stuff to change the condition sharedObject.notifyAll(); } 

这应该为你做的伎俩。 您也可以使用自旋锁执行此操作,但每次执行循环时都需要检查超时。 实际上代码可能实际上有点简单。