开发者

Run code for x seconds in Java?

开发者 https://www.devze.com 2022-12-16 07:16 出处:网络
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 w

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 sig开发者_JS百科nature.

Is there a better way?


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.


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();


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
} 


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


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.


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.


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.


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


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.


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.


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;
}


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


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;
            }
        }
    }
    
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号