Java 等待 x 秒或直到条件变为真
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25325442/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
wait x seconds or until a condition becomes true
提问by user3561614
How to wait x seconds or until a condition becomes true? The condition should be tested periodically while waiting. Currently I'm using this code, but there should be a short function.
如何等待 x 秒或直到条件变为真?在等待期间应定期测试该条件。目前我正在使用此代码,但应该有一个简短的功能。
for (int i = 10; i > 0 && !condition(); i--) {
Thread.sleep(1000);
}
回答by Adrian
Have a look at Condition.
看看条件。
Conditions (also known as condition queues or condition variables) provide a means for one thread to suspend execution (to "wait") until notified by another thread that some state condition may now be true. Because access to this shared state information occurs in different threads, it must be protected, so a lock of some form is associated with the condition. The key property that waiting for a condition provides is that it atomically releases the associated lock and suspends the current thread, just like Object.wait.
A Condition instance is intrinsically bound to a lock. To obtain a Condition instance for a particular Lock instance use its newCondition() method.
条件(也称为条件队列或条件变量)为一个线程提供了一种挂起执行(“等待”)的方法,直到另一个线程通知某个状态条件现在可能为真。因为对这个共享状态信息的访问发生在不同的线程中,它必须受到保护,所以某种形式的锁与条件相关联。等待条件提供的关键属性是它以原子方式释放关联的锁并挂起当前线程,就像 Object.wait 一样。
Condition 实例本质上绑定到锁。要获取特定 Lock 实例的 Condition 实例,请使用其 newCondition() 方法。
EDIT:
编辑:
- Related question Sleep and check until condition is true
- Related question is there a 'block until condition becomes true' function in java?
回答by Micha? Schielmann
Have you thought about some classes from java.util.concurrent - for example a BlockingQueue? You could use:
您是否考虑过 java.util.concurrent 中的一些类 - 例如 BlockingQueue?你可以使用:
BlockingQueue<Boolean> conditionMet = new BlockingQueue<Boolean>;
conditionMet.poll(10,TimeUnit.SECONDS);
And then in the code that changes your condition do this:
然后在更改条件的代码中执行以下操作:
conditionMet.put(true);
EDIT:
编辑:
Another example form java.util.concurrent may be CountDownLatch:
另一个示例形式 java.util.concurrent 可能是 CountDownLatch:
CountDownLatch siteWasRenderedLatch = new CountDownLatch(1);
boolean siteWasRendered = siteWasRenderedLatch.await(10,TimeUnit.SECONDS);
This way you'll wait 10 seconds or until the latch reaches zero. To reach zero all you have to do is:
这样您将等待 10 秒钟或直到闩锁达到零。要达到零,您所要做的就是:
siteWasRenderedLatch.countDown();
This way you won't need to use locks which would be needed in Condition examples presented by @Adrian. I think it's just simpler and straight-forward.
这样你就不需要使用@Adrian 提供的条件示例中需要的锁。我认为它更简单和直接。
And if you don't like the naming 'Latch' or 'Queue' you can always wrap it into your own class called i.e. LimitedTimeCondition:
如果您不喜欢命名“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();
}
}
And the usage would be:
用法是:
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();
}
回答by soru
Assuming you want what you asked for, as opposed to suggestions for redesigning your code, you should look at Awaitility.
假设你想要你所要求的,而不是重新设计代码的建议,你应该看看Awaitility。
For example, if you want to see if a file will be created within the next 10 seconds, you do something like:
例如,如果您想查看是否会在接下来的 10 秒内创建文件,您可以执行以下操作:
await().atMost(10, SECONDS).until(() -> myFile.exists());
It's mainly aimed at testing, but does the specific requested trick of waiting for an arbitrary condition, specified by the caller, without explicit synchronisation or sleep calls. If you don't want to use the library, just read the code to see the way it does things.
它主要针对测试,但执行特定请求的技巧,即等待调用者指定的任意条件,而无需显式同步或睡眠调用。如果您不想使用该库,只需阅读代码即可了解它的工作方式。
Which, in this case, comes down to a similar polling loop to the question, but with a Java 8 lambda passed in as an argument, instead of an inline condtion.
在这种情况下,这归结为与问题类似的轮询循环,但将 Java 8 lambda 作为参数传入,而不是内联条件。
回答by ErstwhileIII
You may want to use something like the code below (where secondsToWait
holds the maximum number of seconds you want to wait to see if the condition()
turns true. The varialbe isCondetionMet
will contain true if the condition was found, or false if the code timed out waiting for the condition.
您可能想要使用类似下面的代码(其中secondsToWait
包含您想要等待以查看是否condition()
变为真的最大秒数。isCondetionMet
如果找到条件,则变量将包含真,如果代码超时等待健康)状况。
long endWaitTime = System.currentTimeMillis() + secondsToWait*1000;
boolean isConditionMet = false;
while (System.currentTimeMillis() < endWaitTime && !isConditionMet) {
isConditionMet = condition();
if (isConditionMet) {
break;
} else {
Thread.sleep(1000);
}
}
回答by Tama
Still i didn't find a solution i think the jdk should come with this feature.
我仍然没有找到解决方案,我认为 jdk 应该带有此功能。
Here what I've implemented with a Functional Interface:
这是我用函数式接口实现的:
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));
}
}
}
}