java 等待x秒或直到条件变为真

mznpcxlj  于 2022-12-10  发布在  Java
关注(0)|答案(7)|浏览(171)

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

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

oknwwptz1#

假设你想要你所要求的,而不是重新设计你的代码的建议,你应该看看Awaitility。
例如,如果您要查看是否会在接下来的10秒内创建文件,请执行以下操作:

await().atMost(10, SECONDS).until(() -> myFile.exists());

它主要用于测试,但也执行特定的请求技巧,即等待调用者指定的任意条件,而不需要显式同步或睡眠调用。如果您不想使用该库,只需阅读代码,了解它的工作方式。
在本例中,这归结为一个与问题类似的轮询循环,但将Java8lambda作为参数而不是内联条件传入。

4sup72z8

4sup72z82#

您是否考虑过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给出的Condition例子中是需要锁的。我认为这样更简单直接。
如果您不喜欢命名“Latch”或“Queue”,您可以将其 Package 到您自己的类中,即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();
}
vatpfxk5

vatpfxk53#

我没有在JDK中找到解决方案。我认为这个特性应该添加到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 met within %s ms",timeoutms));
      }
    }
  }
}
6psbrbz9

6psbrbz94#

看一看Condition
条件(也称为条件队列或条件变量)为一个线程提供了挂起执行的方法因为对该共享状态信息的访问发生在不同的线程中,所以它必须被保护,因此某种形式的锁与条件相关联,等待条件提供的关键属性是它原子地释放关联的锁并挂起当前线程,就像Object. wait一样。
Condition示例本身绑定到锁。若要获取特定Lock示例的Condition示例,请使用其newCondition()方法。
编辑:

mutmk8jj

mutmk8jj5#

您可能希望使用类似下面的代码(其中secondsToWait保存您希望等待以查看condition()是否变为true的最大秒数。如果找到条件,变量isCondetionMet将包含true,如果代码等待条件超时,则包含false。

long endWaitTime = System.currentTimeMillis() + secondsToWait*1000;
        boolean isConditionMet = false;
        while (System.currentTimeMillis() < endWaitTime && !isConditionMet) {
            isConditionMet = condition();
            if (isConditionMet) {
                break;
            } else {
                Thread.sleep(1000);
            }
        }
n8ghc7c1

n8ghc7c16#

我采用了以下改编自原问题的解决方案:

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();
30byixjq

30byixjq7#

使用等待Awaritility:

Awaitility.with().pollDelay(1000, TimeUnit.MILLISECONDS).await().until(() -> true);

相关问题