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