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

use*_*614 8 java sleep conditional-statements

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

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

sor*_*oru 31

假设你想要你想要的东西,而不是重新设计你的代码的建议,你应该看看Awaitility.

例如,如果要查看是否将在接下来的10秒内创建文件,则执行以下操作:

await().atMost(10, SECONDS).until(() -> myFile.exists());
Run Code Online (Sandbox Code Playgroud)

它主要针对测试,但是在没有显式同步或睡眠调用的情况下,执行特定请求的等待调用者指定的任意条件的技巧.如果您不想使用该库,只需阅读代码即可查看其执行方式.

在这种情况下,归结为问题的类似轮询循环,但将Java 8 lambda作为参数传入,而不是内联条件.

  • Awaitility的唯一缺点是对hamcrest-core和hamcrest-lib :( (3认同)
  • [Failsafe](https://github.com/jhalterman/failsafe) 可能更适合在测试环境之外使用。 (3认同)

Mic*_*ann 6

您是否考虑过java.util.concurrent中的一些类 - 例如BlockingQueue?你可以使用:

BlockingQueue<Boolean> conditionMet = new BlockingQueue<Boolean>;
conditionMet.poll(10,TimeUnit.SECONDS);
Run Code Online (Sandbox Code Playgroud)

然后在改变你的条件的代码中执行以下操作:

conditionMet.put(true);
Run Code Online (Sandbox Code Playgroud)

编辑:

java.util.concurrent的另一个示例可能是CountDownLatch:

CountDownLatch siteWasRenderedLatch = new CountDownLatch(1);
boolean siteWasRendered = siteWasRenderedLatch.await(10,TimeUnit.SECONDS);
Run Code Online (Sandbox Code Playgroud)

这样你就会等待10秒或直到闩锁达到零.要达到零,您所要做的就是:

siteWasRenderedLatch.countDown();
Run Code Online (Sandbox Code Playgroud)

这样您就不需要使用@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();
    }
}
Run Code Online (Sandbox Code Playgroud)

用法是:

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();
}
Run Code Online (Sandbox Code Playgroud)


Adr*_*ian 5

看看条件

条件(也称为条件队列或条件变量)为一个线程提供了一种挂起执行(“等待”)的方法,直到另一个线程通知某个状态条件现在可能为真。因为对这个共享状态信息的访问发生在不同的线程中,它必须受到保护,所以某种形式的锁与条件相关联。等待条件提供的关键属性是它以原子方式释放关联的锁并挂起当前线程,就像 Object.wait 一样。

Condition 实例本质上绑定到锁。要获取特定 Lock 实例的 Condition 实例,请使用其 newCondition() 方法。

编辑:

  • 如果您只有一个线程,那么如果只有一个线程在等待,条件如何变为真? (3认同)
  • 但是如果程序只包含一个线程,那么当线程被 sleep 方法捕获时会调用 condition() 吗? (3认同)

Tam*_*ama 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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

}