32

In the code, the variable timer would specify the duration after which to end the while loop, 60 sec for example.

   while(timer) {
    //run
    //terminate after 60 sec
   }
marscom
  • 615
  • 2
  • 11
  • 24
s2000coder
  • 913
  • 2
  • 15
  • 23
  • 1
    Seems we're rehashing an old thread here: http://stackoverflow.com/questions/2550536/java-loop-for-a-certain-duration – Dmitri Nov 23 '10 at 03:28
  • Possible duplicate of [How to timeout a thread](http://stackoverflow.com/questions/2275443/how-to-timeout-a-thread) – vhunsicker Nov 25 '16 at 14:17

4 Answers4

54
long start = System.currentTimeMillis();
long end = start + 60*1000; // 60 seconds * 1000 ms/sec
while (System.currentTimeMillis() < end)
{
    // run
}
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • 9
    but if one iteration of the loop starts when start at 59 seconds and each iteration of the loop takes more than 1 second, you'd go over 60 seconds right? Is this the best that can be done. I'm asking out of pure ignorance. – Ramy Nov 23 '10 at 02:46
  • @Ramy: nope. The `start` and `end` are absolute times, measured in milliseconds since the epoch (midnight, Jan 1 1970 UTC). There is no rollover. – Matt Ball Nov 23 '10 at 02:50
  • 6
    ok, but the check only happens at the start of the loop. So, if at the start of the loop, say 59 seconds have elapsed, and each iteration of the loop takes, say, 5 seconds. The next time the while loop is condition is checked, 64 seconds will have elapsed. Right, or am I missing something? – Ramy Nov 23 '10 at 02:55
  • @Ramy: you're still missing it. The loop starts at zero milliseconds (for all intents and purposes). Think of it the way the math has set it up: before I enter the loop, I get the current time. To figure out when the loop should end, I add 60 seconds (60,000 ms) to the current time. The loop condition is false in 60 seconds. – Matt Ball Nov 23 '10 at 02:59
  • 6
    I believe Ramy is correct. Assume the work in the loop takes 7 seconds to complete. After one run you're at 7 seconds, then 14... until you have completed 8 iterations, for a total of 56 seconds. The check will succeed (because you are under 60s) but then the calculations will take 7 seconds. By the time the check is done again, you're at 63 seconds. That's 5% over time. – MBCook Nov 23 '10 at 03:03
  • Right, I'm with you. But what if we get to sixty seconds INSIDE THE LOOP? This could absolutely be the best way of doing this but MBCook sees my point. – Ramy Nov 23 '10 at 03:04
  • This solution is fine, there's no hard limit in my program. Thank you guys! – s2000coder Nov 23 '10 at 04:01
  • @MBCook: I don't see your point. What's the better solution? Interrupt the computation in the middle of the loop? Doubtful. – Matt Ball Nov 23 '10 at 13:45
  • I would tend to agree with Ramy. Your suggestion only works as long as the code within the loop doesn't last longer than end-start. If the bit called //run lasts 61 seconds --> fail. – Andrew Magerman May 23 '14 at 07:36
  • 1
    @MattBall Why is it doubtful to interrupt a computation? It really depends on your needs. Probably you got some downvotes, because you did not explain, what your code really aims to do -> preventing the "run"-code being executed _again_ after 60 seconds. Which is quite different from "terminate after 60 sec", which people - reading the question - would probably have been expected to do. – Murmel Sep 06 '16 at 22:03
  • How about set for 8 minutes? My spring MVC controller start executing again after 5 minutes. Any idea? – Vanan Jul 29 '21 at 07:19
29

you should try the new Java Executor Services. http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html

With this you don't need to program the loop the time measuring by yourself.

public class Starter {

    public static void main(final String[] args) {
        final ExecutorService service = Executors.newSingleThreadExecutor();

        try {
            final Future<Object> f = service.submit(() -> {
                // Do you long running calculation here
                Thread.sleep(1337); // Simulate some delay
                return "42";
            });

            System.out.println(f.get(1, TimeUnit.SECONDS));
        } catch (final TimeoutException e) {
            System.err.println("Calculation took to long");
        } catch (final Exception e) {
            throw new RuntimeException(e);
        } finally {
            service.shutdown();
        }
    }
}
d0x
  • 11,040
  • 17
  • 69
  • 104
5

If you can't go over your time limit (it's a hard limit) then a thread is your best bet. You can use a loop to terminate the thread once you get to the time threshold. Whatever is going on in that thread at the time can be interrupted, allowing calculations to stop almost instantly. Here is an example:

Thread t = new Thread(myRunnable); // myRunnable does your calculations

long startTime = System.currentTimeMillis();
long endTime = startTime + 60000L;

t.start(); // Kick off calculations

while (System.currentTimeMillis() < endTime) {
    // Still within time theshold, wait a little longer
    try {
         Thread.sleep(500L);  // Sleep 1/2 second
    } catch (InterruptedException e) {
         // Someone woke us up during sleep, that's OK
    }
}

t.interrupt();  // Tell the thread to stop
t.join();       // Wait for the thread to cleanup and finish

That will give you resolution to about 1/2 second. By polling more often in the while loop, you can get that down.

Your runnable's run would look something like this:

public void run() {
    while (true) {
        try {
            // Long running work
            calculateMassOfUniverse();
        } catch (InterruptedException e) {
            // We were signaled, clean things up
            cleanupStuff();
            break;           // Leave the loop, thread will exit
    }
}

Update based on Dmitri's answer

Dmitri pointed out TimerTask, which would let you avoid the loop. You could just do the join call and the TimerTask you setup would take care of interrupting the thread. This would let you get more exact resolution without having to poll in a loop.

MBCook
  • 14,424
  • 7
  • 37
  • 41
  • That's not how `.interrupt()` works, though. Unless the thread is blocked, it just sets the `interrupted` flag, the thread still has to check it to stop execution. Also, `InterruptedException` is a checked exception, you can't just throw it around some arbitrary code (your example will not compile). – Dmitri Nov 23 '10 at 03:18
2

Depends on what the while loop is doing. If there is a chance that it will block for a long time, use TimerTask to schedule a task to set a stopExecution flag, and also .interrupt() your thread.

With just a time condition in the loop, it could sit there forever waiting for input or a lock (then again, may not be a problem for you).

Dmitri
  • 8,999
  • 5
  • 36
  • 43