Run code for x seconds in Java?
Asked Answered
S

13

35

I'd like to write a java while loop that will iterate for 15 seconds. One way I thought to do this would be to store the current system time + 15sec and then compare that to the current time in the while loop signature.

Is there a better way?

Somatoplasm answered 8/1, 2010 at 16:46 Comment(2)
Do you need to do any work in the 15s or just wait?Acetometer
If you need to do work within the 15seconds, check my answer below. I show you a better way using thread, sleep while still being able to do work but importantly without polling system time. https://mcmap.net/q/424305/-run-code-for-x-seconds-in-javaBarto
P
68

The design of this depends on what you want doing for 15s. The two most plausible cases are "do this every X for 15s" or "wait for X to happen or 15s whichever comes sooner", which will lead to very different code.

Just waiting

Thread.sleep(15000)

This doesn't iterate, but if you want to do nothing for 15s is much more efficient (it wastes less CPU on doing nothing).

Repeat some code for 15s

If you really want to loop for 15s then your solution is fine, as long as your code doesn't take too long. Something like:

long t= System.currentTimeMillis();
long end = t+15000;
while(System.currentTimeMillis() < end) {
  // do something
  // pause to avoid churning
  Thread.sleep( xxx );
}

Wait for 15s or some other condition

If you want your code to be interrupted after exactly 15s whatever it is doing you'll need a multi-threaded solution. Look at java.util.concurrent for lots of useful objects. Most methods which lock (like wait() ) have a timeout argument. A semaphore might do exactly what you need.

Popularize answered 8/1, 2010 at 16:48 Comment(2)
More than likely he wants the thread to do something for 15 seconds, so sleeping would be counterproductive.Nervine
This example did not help me because I wanted to execute this code in multiple threads. If you want check my solution down to this page.Charity
B
5

As already mentioned by other posters, if you just want the thread to pause for some time use Thread.sleep().

If you want the thread to do something, but want to make it stop after a while, use something like:

class Foo implements Runnable {
    private volatile boolean killed = false;

    public void run() {
        while (!killed) {
            try { doOnce(); } catch (InterruptedException ex) { killed = true; }
        }
    }

    public void kill() { killed = true; }
    private void doOnce() throws InterruptedException { /* .. */ }
}

and from the main thread, do:

Foo foo = new Foo(); 
Thread thread = new Thread(foo);
thread.start();

/* when you want to stop it */
foo.kill();
thread.interrupt();
Bettyannbettye answered 8/1, 2010 at 16:59 Comment(2)
please do not ignore the InterruptedException. If something wants to interrupt, so do it (at least exit the loop).Alysonalysoun
@Carlos Thanks! I edited the code to exit the loop on interruption.Bettyannbettye
Z
5

Your general approach seems fine although you may want to see if the current time is greater than the point you want to stop, otherwise, you might be running for a long time.

The alternative is to run a timer/thread that sets a flag after 15 seconds have elapsed. This flag would have to be marked as volatile otherwise your loop might not see the change occur in the value.

The choice if you care about efficiency is which is more expensive, getting the system time once per loop or accessing a volatile variable? I don't know which one is more efficient - you could benchmark it if it's really important.

For simple, maintainable code, I'd choose the timer check approach:

long endTime = System.currentTimeMillis() + 15000
while (System.currentTimeMillis() < endTime) {
  //loop
} 
Zamir answered 8/1, 2010 at 17:3 Comment(0)
A
3

try this:

public class SleepMessages {
    public static void main(String args[]) throws InterruptedException {
        String importantInfo[] = {
            "Mares eat oats",
            "Does eat oats",
            "Little lambs eat ivy",
            "A kid will eat ivy too"
        };

        for (int i = 0; i < importantInfo.length; i++) {
            //Pause for 15 seconds
            Thread.sleep(15000);
            //Print a message
            System.out.println(importantInfo[i]);
        }
    }
}

more info : here

Allie answered 8/1, 2010 at 16:49 Comment(0)
C
2

Never check for current time in a tight loop.

Otherwise somebody with a laptop can get get his/her lap burned by an overheated CPU. I heard the stories of this actually happening.

Cru answered 8/1, 2010 at 16:58 Comment(1)
Interesting - the timer value will be updated every time the kernel ticks anyway so timer operations while not free should be cheap. Doing anything in a tight loop will warm the CPU up.Zamir
J
1

For the java.util.concurrent approach, refer to Chapter 6 of Java Concurrency in Practice (section 6.3.7 Placing time limits on tasks, page 131).

Code example: Fetching an advertisement with a time budget.

Jonijonie answered 8/1, 2010 at 18:49 Comment(0)
O
1

You can use AOP and a @Timeable annotation from jcabi-aspects (I'm a developer):

@Timeable(limit = 1, unit = TimeUnit.SECONDS)
String load(String resource) {
  // do this check regularly:
  if (Thread.currentThread.isInterrupted()) {
    throw new IllegalStateException("time out");
  }
  // execution as normal
}

When time limit is reached your thread will get interrupted() flag set to true and it's your job to handle this situation correctly and to stop execution.

Oxyacetylene answered 5/4, 2013 at 18:2 Comment(0)
N
0

Assuming you want the loop to do something sensible, you might find it faster to check a volatile flag. Have another thread wait 15 seconds (or use a timer) and then set it.

Alternatively, if you know roughly how long the loop body will take, run it a few hundred times, say, and do the time check in an outer loop.

final long start = System.nanoTime();
do {
    for (int i=0; i<200, ++i) {
        ...
    }
} while (System.nanoTime()-start < 15L*1000L*1000L*1000L);

System.nanoTime should not get confused by system clock changes. Use of long literal numbers is important.

Nolte answered 8/1, 2010 at 16:53 Comment(0)
S
0

You might be interested in scheduling a TimerTask that stops another thread or changes the condition of your loop.

Stepdaughter answered 8/1, 2010 at 16:53 Comment(0)
J
0

A solution similar to @Tom Hawtin without an arbitary loop size.

final long end = System.nanoTime() + 15 * 1000 * 1000 * 1000L;
int loop = 1;
do {
    for (int i=0; i<loop; ++i) {
        ...
    }
    loop++;
} while (System.nanoTime() < end);

In this case the size of the inner loop will start small but grow in size if the loop is particularly quick. If it is slow enough, it might only iterate once.

Johnsson answered 9/1, 2010 at 13:36 Comment(0)
P
0

Here is my suggestion and it's working good for me :)

StoppingTime = 15 ;
int loop = 1;
long StartTime = System.currentTimeMillis() / 1000 ;
for (int i=0; i<loop; ++i) {
    // your code here

    loop++;
    if (((System.currentTimeMillis()/1000) - StartTime) > StoppingTime)
        loop=0;
}
Proportionate answered 3/9, 2013 at 16:7 Comment(0)
C
0

I would suggest you do this with the timer class avoiding the Thread.sleep(xxx); method.

for example:

import java.util.Timer;
import java.util.TimerTask;

public class TimerExample {
    private int globalTimer = 0;
    private int limitTimer = 15;

    public static void main(String[] args) {
        new TimerExample();
    }

    public TimerExample() {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                globalTimer++;
                // DO YOUR CODE HERE
                System.out.println("running");
                if (globalTimer == limitTimer) {
                    timer.cancel();
                }
            }
        }, 0, 1000);
    }
}
Charity answered 19/1, 2016 at 12:31 Comment(0)
B
0

Use an object array as your local variable to pass to the thread. In your loop check to see if that variable has been changed by your thread.

NB Its important to use an Array Of Object since a thread's run method will be able to access it even if it was a local variable.

How?

  1. Create a new Thread

  2. In the run method sleep(1000*15) for 15 seconds

  3. Update your local variable.

    //The thread method
    public static boolean[] delay(int seconds) {
        final boolean[] cont = new boolean[1];
        cont[0] = true;
        Thread thread = new Thread() {
            @Override
            public void run() {
                try {
                    sleep(1000 * seconds);
                    cont[0] = false;
                } catch (InterruptedException ex) {
                }
            }
        };
        thread.start();
        return cont;
    }
    
    //The loop method
    public void dance(){
        //here we call our delay method time it for 15 seconds.
        final boolean[] delay = delay(15);
    
        for (int i = 0; i < size; i++) {
            //your code here.
    
            if (delay[0] == false) { //check if delay has been changed to false and break.
                break;
            }
        }
    }
    
Barto answered 25/3, 2022 at 2:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.