等待x秒或直到条件成立为止

时间:2014-08-15 11:12:52

标签: java conditional-statements sleep

如何等待x秒或直到条件变为真?应该在等待时定期测试这种情况。目前我正在使用此代码,但应该有一个简短的功能。

for (int i = 10; i > 0 && !condition(); i--) {
    Thread.sleep(1000);
}

6 个答案:

答案 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();