14

Is there a way I can do a for loop for a certain amount of time easily? (without measuring the time ourselves using System.currentTimeMillis() ?)

I.e. I want to do something like this in Java:

int x = 0;
for( 2 minutes )  {
   System.out.println(x++);
}

Thanks

Lydon Ch
  • 8,637
  • 20
  • 79
  • 132
  • 4
    Do you want to continuously and furiously print something on the screen for the duration of 2 minutes? Or you want to print once every 2 minutes? – Bruno Reis Mar 31 '10 at 04:45
  • 1
    I want to continuously and furiously print something on the screen for the duration of 2 minutes – Lydon Ch Mar 31 '10 at 05:46
  • 5
    Most answers are completely wrong saying you can't do it without measuring the time yourself. You definitely *CAN* do it without using *System.currentTimeMillis()*. For example you *could* schedule a Timer set to two minutes that would change a volatile boolean (say *shouldStop*) and use a *while(!shouldStop) {...}* but really for something that simple I don't see what's wrong with using *System.currentTimeMillis()* (note that even if I prefer System.currentTimeMillis() doesn't change the **fact** that most answers are completely wrong and wrongly upvoted). – SyntaxT3rr0r Mar 31 '10 at 05:58
  • 1
    Btw Java not being real-time there's no guarantee, even constantly checking *System.currentTimeMillis()*, that you'll be able to run for *exactly* two minutes: your very thread furiously checking the time might get "scheduled out" and you may "miss" the "exact" two minutes spot anyway, so arguing that a Timer may miss the mark would be pretty retarded, because a thread constantly checking System.currentTimeMillis() could miss the mark too :) – SyntaxT3rr0r Mar 31 '10 at 06:06
  • Oh WizardOfOdds, so passionate, so angry. I have a friend for you. – Tim Bender Mar 31 '10 at 06:22
  • @WizardOfOdds yes i think Timer works for this purpose, but then I have to check the boolean shouldStop manually. – Lydon Ch Mar 31 '10 at 06:46
  • @portalet - you either have to poll the system clock or test a flag; see my answer. – Stephen C Mar 31 '10 at 06:59

10 Answers10

31

No, there isn't a built-in construct which does that.

I want to point out that you should not use System.currentTimeMillis() for performing, or delaying, a task for a specified time period. Instead use System.nanoTime(). The former method is inaccurate in Windows, while the latter method is accurate regardless of OS. You can use TimeUnit enum to easily go between time in milliseconds, or any other time unit, to time in nanoseconds.

for (long stop=System.nanoTime()+TimeUnit.SECONDS.toNanos(2);stop>System.nanoTime();) {
  /*
   * Hammer the JVM with junk
   */
}
Peter Lang
  • 54,264
  • 27
  • 148
  • 161
Tim Bender
  • 20,112
  • 2
  • 49
  • 58
  • Thanks. Just curious now about how much time the time checking takes. – Lydon Ch Mar 31 '10 at 15:09
  • Oh no. Using nanoseconds does NOT make it valid to waste CPU cycles like that! Never ever program a loop, monitor the time and do - nothing! Instead: use Thread.sleep(...) do allow the system to do *useful* things while you don't want anything from it!! – Zordid Mar 31 '10 at 15:14
  • 1
    @Zordid - The OP wants to do something useful during this loop, hence the comment I placed in the loop. @portoalet - I'm not sure, it just retrieves the high-resolution timer as opposed to another timer. So it should be the same as System.currentTimeMillis. – Tim Bender Mar 31 '10 at 16:34
  • 1
    Well, it's true that `System.currentTimeMillis()` has a coarser resolution than `nanoTime()`, but it's still ~10-15ms. So unless you want to measure in the ms range, `System.currentTimeMillis()` is perfectly OK. Also I think `System.currentTimeMillis()` is somewhat faster than `nanoTime()` (though this depends on the JVM and will not usually make a difference). – sleske Sep 23 '10 at 21:50
  • @Zordid, This could be useful in certain circumstances like Performance Load Testing we push inside the loop – stuckedunderflow Nov 29 '14 at 03:00
  • @TimBender: but the OP explicitly stated he does not want to do any measuring "like" System.currentTimeMillis() himself. Thus this answer simply does not fit in any case... saying, no use System.nanoTime() instead... :-) – Zordid Dec 13 '14 at 13:22
  • @Zordid my answer to the predicate was no, there is not a built-in method. I added that the high resolution clock would be better for this type of use. I also up voted an answer below with a good alternative that makes no timeliness guarantees. – Tim Bender Dec 13 '14 at 20:06
  • @TimBender the input/duration is given in minutes or nano-seconds in above code-snippet? – hirosht Mar 02 '21 at 07:33
  • @Hirosht the input is in seconds as dictated by the `TimeUnit.SECONDS` enum. See: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/TimeUnit.html – Tim Bender May 04 '21 at 06:58
14

I think that this is what you want:

private final Thread thisThread = Thread.current();
private final int timeToRun = 120000; // 2 minutes;

new Thread(new Runnable() {
    public void run() {
        sleep(timeToRun);
        thisThread.interrupt();
    }
}).start();

while (!Thread.interrupted()) {
    // do something interesting.
}

This avoids doing repeated syscalls to get the system clock value (which can be rather expensive) and polls the current thread's interrupted flag instead (much cheaper).

EDIT

There is actually no safe alternative to polling the clock or polling a flag. In theory, you could modify the above fragment to call the deprecated Thread.stop() method instead of Thread.interrupt().

(I do NOT recommend using Thread.stop() and friends. They are flawed, and dangerous to use. I'm just posing this as a theoretical alternative.)

EDIT 2

Just to point out that using Thread.interrupt() has the advantages over setting a shared flag:

  • Thread.interrupt() will cause certain blocking I/O and synchronization methods to unblock and throw a checked exception. Updating a shared flag won't do this.

  • Some third-party libraries also check the interrupt flag to see if they should stop what they are currently doing.

  • If your loop involves calls to other methods, etc, Thread.interrupt() means that you don't need to worry about those methods can access the flag ... if they need to.

EDIT 3

Just to add that sleep(N) is not guaranteed to wake the sleeping thread up after exactly N milliseconds. But under normal circumstances, it will be reasonably close.

N3dst4
  • 6,360
  • 2
  • 20
  • 34
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
3

I made a simple, but sucky, implementation for this problem. I wanted to avoid Timer and TimeTask and ended up with this quickfix solution.

The main idea is that I simply wanted to create an independed countdown timer which I could just start and call isFinished() to check if the countdown is finished.

package RIPv3;

/**
 * Creates a countdown timer which runs its own thread and uses CountdownTimerThread,                which runs yet another
 * thread.
 *
 * start() method is called to start the countdown.
 * isFinished() method is called to check if the countdown is finished or not.
 * 
 * ! Be Aware!
 * This is a quickfix and sucky implementation.
 * There will be a small delay. This is not accurate.
 * 
 * @author Endre Vestbø
 * @version 1.0 (09.05.2011)
 */
public class CountdownTimer extends Thread {
/* Countdown timer */
private CountdownTimerThread timer;

/**
 * Creates a new timer and sets time to count down
 * @param time
 *          Time to count down
 */
public CountdownTimer(long time) {
    this.timer = new CountdownTimerThread(time);
}

public void run() {
    this.timer.start();
}

/**
 * @return
 *      False if timer is running, else true
 */
public boolean isFinished() {
    if(this.timer.getState() == Thread.State.TERMINATED)
        return true;

    return false;
}   
}

 package RIPv3;

/**
 * Used by CountdownTimer to count down time.
 * 
 * @author Endre Vestbø
 * @version 1.0  (09.05.2011)
 *
 */
public class CountdownTimerThread extends Thread {
private long time;

/** Create a new timer */
public CountdownTimerThread(long time) {
    this.time = time;
}

/**
 * Start a countdown
 * @param period
 *      Period to count down given in milliseconds
 */
public void run() {
    try {
        sleep(this.time);
    } catch (InterruptedException e) {

    }
}
}
1

No. That is sort of a strange request considering how simple it would be to simply write a function that uses System.currentTimeMillis() (or whichever time function you choose). More context of the situation might be in order.

Joe Phillips
  • 49,743
  • 32
  • 103
  • 159
  • +0.5 for beating me by 23 seconds. +0.5 for pointing out oddity of the request. –  Mar 31 '10 at 04:46
  • @MaxGuernseyll - actually, calling `System.currentTimeMillis()` can be rather expensive. On some platforms, it will entail making a system call; i.e. hundreds of machine instructions. – Stephen C Mar 31 '10 at 07:29
  • 3
    Strange request doesn't imply silly question? If you say so ... Either way, "no" is clearly an incorrect answer. – Stephen C Mar 31 '10 at 14:44
  • @Stephen On average, how many system calls are made in 1 second if we use System.currentTimeMillis() ? And which platform performs better, i.e. least system calls made? – Lydon Ch Mar 31 '10 at 15:18
  • @portolet - I cannot give you definitive answers to these questions. – Stephen C Mar 31 '10 at 21:56
1

Here is another suggestion:

public class TimerLoop {
    private final AtomicBoolean loop = new AtomicBoolean();

public void run(Runnable runnable, long duration, TimeUnit timeUnit) {
    loop.set(true);
    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            loop.set(false);
        }
    };
    Timer timer = new Timer();
    timer.schedule(task, timeUnit.toMillis(duration));
    while (loop.get()) {
        runnable.run();
    }
}

}

The method executes the run() method of the provided Runnable repeatedly until the timer expires.

Considerations:

  • The time will be approximate.
  • Be careful how you implement the run() method as it will potentially consume all your CPU power.
  • The implementation is not thread-safe unless you create a new instance of the TimerLoop class for each Runnable that you would like to execute.
matsev
  • 32,104
  • 16
  • 121
  • 156
0

I don't think there is a way to loop for a certain period of time without checking to see if you've looped for a certain period of time.

  • 1
    Well someone, somewhere, has to check the time. Even if you use a ScheduledFuture or TimerTask or even a Quartz component, inside that code there will be a timing mechanism for sure. – Adriaan Koster Mar 31 '10 at 08:16
  • @Adriaan - not necessarily. On Windows and Linux the C sleep library function is implemented as a syscall; see http://cboard.cprogramming.com/c-programming/109721-sleep-system-call.html . And I expect that Java Thread.sleep(...) calls the C library function under the covers. – Stephen C Mar 31 '10 at 13:40
  • @MaxGuernseylll - of course the sleep syscall has *"something to do with time"*. But the mechanism is not inside the code of `ScheduledFuture` etc. It is in the OS kernel. And it most certainly does **NOT** entail *"checking to see if you've looped for a certain period of time"*. – Stephen C Mar 31 '10 at 23:12
  • @MaxGuernseylll - BTW, I flagged your comment as offensive. Kindly refrain from implying that I use illegal drugs. – Stephen C Apr 01 '10 at 04:01
  • @Max @Stephen does a mod have to lock a post? –  Aug 02 '10 at 13:54
0

Depending on your use case either of the two sleep() methods in class Thread might fit the bill, but it sounds like you have to fuss with System.currentTimeMillis(), which seems strange.

Thread thread = Thread.currentThread();
thread.sleep(10);      // 10 milliseconds
thread.sleep(12, 345); // 12 milliseconds and 345 nanoseconds.
Jim Ferrans
  • 30,582
  • 12
  • 56
  • 83
  • Unfortunately, Thread.sleep takes a SUGGESTED time to sleep as an argument... it should definitely sleep at LEAST that many ms, not exactly. You'll still want to check to see how much time has actually elapsed. – billjamesdev Mar 31 '10 at 04:54
0

Loops iterate over value comparison and not for duration. So without yourself assigning and comparing the system time, you cannot do it. If however you wish it be intuitive, then you can have a function that internally uses milliseconds, but takes Minutes as argument and use it.

And No, you cannot use threads or the sleep method in it, because that does not ensure the exact time. If your processor is busy with some other thread after the given time elapses, then your thread will continue to wait.

Vaishak Suresh
  • 5,735
  • 10
  • 41
  • 66
0

In your question you mention

(without measuring the time ourselves using System.currentTimeMillis() ?)

Here is how to, without using any system time of any sort. Don't forget to check the code sample.

  1. Define a local object array to be manipulated by your thread
  2. Create a new Thread
  3. In the run method sleep(1000*15) for 15 seconds
  4. Update your local variable.

Check this good code sample here https://stackoverflow.com/a/71611647/3190214

katwekibs
  • 1,342
  • 14
  • 17
0
LocalDateTime then = LocalDateTime.now();
while (true) {


// logic
if (ChronoUnit.SECONDS.between(then, LocalDateTime.now()) >= 20) break;
}
Bayram Binbir
  • 1,531
  • 11
  • 11
  • Your answer could be improved by adding more information on what the code does and how it helps the OP. – Tyler2P Jul 31 '22 at 08:49