简体   繁体   中英

How to exit a while loop after a certain time?

I have a while loop and I want it to exit after some time has elapsed.

For example:

while(condition and 10 sec has not passed){

}
long startTime = System.currentTimeMillis(); //fetch starting time
while(false||(System.currentTimeMillis()-startTime)<10000)
{
    // do something
}

Thus the statement

(System.currentTimeMillis()-startTime)<10000

Checks if it has been 10 seconds or 10,000 milliseconds since the loop started.

EDIT

As @Julien pointed out, this may fail if your code block inside the while loop takes a lot of time.Thus using ExecutorService would be a good option.

First we would have to implement Runnable

class MyTask implements Runnable
{
    public void run() { 
        // add your code here
    }
}

Then we can use ExecutorService like this,

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.invokeAll(Arrays.asList(new MyTask()), 10, TimeUnit.SECONDS); // Timeout of 10 seconds.
executor.shutdown();

Proposed and accepted solutions won't do the trick.

It won't stop the loop after 10 seconds. Imagine the code in your loop takes 20 seconds to process and is called at 9.9 seconds. Your code would exit after 29.9 seconds of execution.

If you want to exactly stop after 10 seconds, you have to execute your code in an external thread that you will kill after a certain timeout.

Existing solutions have already been proposed here and there

Something like:

long start_time = System.currentTimeMillis();
long wait_time = 10000;
long end_time = start_time + wait_time;

while (System.currentTimeMillis() < end_time) {
   //..
}

Should do the trick. If you need other conditions as well then just add them to the while statement.

Do not use this

System.currentTimeMillis()-startTime

It may cause hang on host machine time change. Better use this way:

Integer i = 0;
            try {
                while (condition && i++ < 100) {
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

(100*100 = 10 sec timeout)

For synchron calls you can use something like this:

    private void executeSomeSyncronLongRunningProccess()  {
        Duration duration = Duration.ofSeconds(5);
        Predicate<String> condition = x -> x.equals("success");
        Supplier<String> codeToExecute = () -> {
            //Your code to execute here
            return "success";
        };
        try {
            String s = runOrTimeout(duration, condition, codeToExecute);
        } catch (ExecutionException e) {
            LOGGER.error("During execution is error occurred", e);
            throw new RuntimeException(e);
        } catch (TimeoutException e) {
            LOGGER.error("Failed to complete task in {} seconds.", duration.getSeconds());
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            LOGGER.error("Failed to complete task in {} seconds.", duration.getSeconds());
            throw new RuntimeException(e);
        }
    }

   private String runOrTimeout(Duration timeout, Predicate<String> conditionOnSuccess, Supplier<String> codeToExecute) throws InterruptedException, ExecutionException, TimeoutException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future<String> pollQueryResults = executorService.submit(() -> {
            String result = null;
            boolean isRunning = true;
            while (isRunning) {
                result = codeToExecute.get();
                if (conditionOnSuccess.test(result)) {
                    isRunning = false;
                }
            }
            return result;
        });
        return pollQueryResults.get(timeout.getSeconds(), TimeUnit.SECONDS);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM