如何等待x秒或直到条件变为真?应该在等待时定期测试这种情况。目前我正在使用此代码,但应该有一个简短的功能。
for (int i = 10; i > 0 && !condition(); i--) {
Thread.sleep(1000);
}
答案 0 :(得分:27)
假设你想要你所要求的,而不是重新设计代码的建议,你应该看看Awaitility。
例如,如果您想查看是否会在接下来的10秒内创建文件,您可以执行以下操作:
await().atMost(10, SECONDS).until(() -> myFile.exists());
它主要针对测试,但是在没有显式同步或睡眠调用的情况下,执行特定请求的等待调用者指定的任意条件的技巧。如果您不想使用该库,只需阅读代码即可查看其执行方式。
在这种情况下,归结为问题的类似轮询循环,但是将Java 8 lambda作为参数传入,而不是内联条件。
答案 1 :(得分:6)
您是否考虑过java.util.concurrent中的一些类 - 例如BlockingQueue? 你可以使用:
BlockingQueue<Boolean> conditionMet = new BlockingQueue<Boolean>;
conditionMet.poll(10,TimeUnit.SECONDS);
然后在改变条件的代码中执行此操作:
conditionMet.put(true);
修改强>
java.util.concurrent的另一个示例形式可能是CountDownLatch:
CountDownLatch siteWasRenderedLatch = new CountDownLatch(1);
boolean siteWasRendered = siteWasRenderedLatch.await(10,TimeUnit.SECONDS);
这样你就会等待10秒或直到闩锁达到零。为了达到零,你所要做的就是:
siteWasRenderedLatch.countDown();
这样您就不需要使用@Adrian提供的条件示例中需要的锁。我认为这更简单直接。
如果您不喜欢命名'Latch'或'Queue',您可以随时将其包装到您自己的类中,即名为LimitedTimeCondition:
public class LimitedTimeCondition
{
private CountDownLatch conditionMetLatch;
private Integer unitsCount;
private TimeUnit unit;
public LimitedTimeCondition(final Integer unitsCount, final TimeUnit unit)
{
conditionMetLatch = new CountDownLatch(1);
this.unitsCount = unitsCount;
this.unit = unit;
}
public boolean waitForConditionToBeMet()
{
try
{
return conditionMetLatch.await(unitsCount, unit);
}
catch (final InterruptedException e)
{
System.out.println("Someone has disturbed the condition awaiter.");
return false;
}
}
public void conditionWasMet()
{
conditionMetLatch.countDown();
}
}
用法是:
LimitedTimeCondition siteRenderedCondition = new LimitedTimeCondition(10, TimeUnit.SECONDS);
//
...
//
if (siteRenderedCondition.waitForConditionToBeMet())
{
doStuff();
}
else
{
System.out.println("Site was not rendered properly");
}
//
...
// in condition checker/achiever:
if (siteWasRendered)
{
condition.conditionWasMet();
}
答案 2 :(得分:5)
我仍然找不到解决方案,我认为jdk应该附带此功能。
这是我用功能界面实现的:
import java.util.concurrent.TimeoutException;
import java.util.function.BooleanSupplier;
public interface WaitUntilUtils {
static void waitUntil(BooleanSupplier condition, long timeoutms) throws TimeoutException{
long start = System.currentTimeMillis();
while (!condition.getAsBoolean()){
if (System.currentTimeMillis() - start > timeoutms ){
throw new TimeoutException(String.format("Condition not meet within %s ms",timeoutms));
}
}
}
}
答案 3 :(得分:4)
查看Condition。
条件(也称为条件队列或条件变量) 为一个线程提供暂停执行的手段(到#34;等待&#34;)直到 另一个线程通知某些状态条件现在可能是真的。 因为访问此共享状态信息的方式不同 线程,它必须受到保护,因此某种形式的锁相关联 有条件的。等待条件的关键属性 提供的是它以原子方式释放相关的锁和 暂停当前线程,就像Object.wait。
一样一个Condition实例本质上绑定到一个锁。获得一个 特定Lock实例的条件实例使用它 newCondition()方法。
编辑:
答案 4 :(得分:1)
您可能希望使用类似下面的代码(其中secondsToWait
包含您希望等待condition()
变为真的最大秒数。变量isCondetionMet
将如果找到条件则包含true;如果代码超时则等于该条件。
long endWaitTime = System.currentTimeMillis() + secondsToWait*1000;
boolean isConditionMet = false;
while (System.currentTimeMillis() < endWaitTime && !isConditionMet) {
isConditionMet = condition();
if (isConditionMet) {
break;
} else {
Thread.sleep(1000);
}
}
答案 5 :(得分:0)
我正在对原始问题的解决方案进行以下修改:
public class Satisfied {
public static boolean inTime(Callable<Boolean> condition, int timeoutInSecs) {
int count;
try {
for (count = 1; count < timeoutInSecs * 20 && !condition.call(); count++)
Thread.sleep(50);
return (count < timeoutInSecs * 20);
} catch (Exception e) {
throw new AssertionError(e.getMessage());
}
}
}
在测试中使用时,它看起来像这样:
assertThat(Satisfied.inTime(() -> myCondition(), 5)).isTrue();