wait x seconds or until a condition becomes true

眉间皱痕 提交于 2020-05-25 12:12:45

问题


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.

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

回答1:


Assuming you want what you asked for, as opposed to suggestions for redesigning your code, you should look at Awaitility.

For example, if you want to see if a file will be created within the next 10 seconds, you do something like:

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.




回答2:


Have you thought about some classes from java.util.concurrent - for example a BlockingQueue? You could use:

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:

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:

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.

And if you don't like the naming 'Latch' or 'Queue' you can always wrap it into your own class called i.e. 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();
}



回答3:


Still i didn't find a solution i think the jdk should come with this feature.

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));
      }
    }
  }
}



回答4:


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.

EDIT:

  • Related question Sleep and check until condition is true
  • Related question is there a 'block until condition becomes true' function in java?



回答5:


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.

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


来源:https://stackoverflow.com/questions/25325442/wait-x-seconds-or-until-a-condition-becomes-true

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!