Выполнить код на х секунд в Java? - PullRequest
24 голосов
/ 08 января 2010

Я хотел бы написать цикл Java, который будет повторяться в течение 15 секунд. Один из способов сделать это - сохранить текущее системное время + 15 секунд, а затем сравнить его с текущим временем в сигнатуре цикла while.

Есть ли лучший способ?

Ответы [ 12 ]

53 голосов
/ 08 января 2010

Дизайн этого зависит от того, что вы хотите делать в течение 15 секунд. Два наиболее вероятных случая: «делать это каждые X в течение 15 секунд» или «ждать, пока произойдет X, или 15 секунд, в зависимости от того, что наступит раньше», что приведет к совершенно другому коду.

Просто жду

Thread.sleep (15000)

Это не повторяется, но если вы хотите ничего не делать в течение 15 секунд, это намного более эффективно (оно тратит меньше ресурсов процессора на бездействие).

Повторите некоторый код в течение 15 с

Если вы действительно хотите зациклить на 15 секунд, тогда ваше решение в порядке, если ваш код не займет слишком много времени. Что-то вроде:

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

Подождите 15 секунд или другое состояние

Если вы хотите, чтобы ваш код прерывался ровно через 15 секунд, вам понадобится многопоточное решение. Посмотрите на java.util.concurrent для множества полезных объектов. Большинство методов, которые блокируются (например, wait ()), имеют аргумент timeout. семафор может делать именно то, что вам нужно.

4 голосов
/ 08 января 2010

Как уже упоминалось другими авторами, если вы просто хотите, чтобы нить приостановилась на некоторое время, используйте Thread.sleep().

Если вы хотите, чтобы поток что-то делал, но хотите через некоторое время остановить его, используйте что-то вроде:

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 { /* .. */ }
}

и из основного потока сделайте:

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

/* when you want to stop it */
foo.kill();
thread.interrupt();
3 голосов
/ 08 января 2010

попробуйте это:

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

подробнее: здесь

2 голосов
/ 08 января 2010

Ваш общий подход выглядит хорошо, хотя вы можете захотеть посмотреть, больше ли текущее время, чем точка, которую вы хотите остановить, в противном случае, вы можете работать долго.

Альтернативой является запуск таймера / потока, который устанавливает флаг по истечении 15 секунд. Этот флаг должен быть помечен как изменчивый, иначе ваш цикл может не увидеть изменения в значении.

Выбор, если вы заботитесь об эффективности, является более дорогостоящим: получить системное время один раз за цикл или получить доступ к изменяемой переменной? Я не знаю, какой из них более эффективен - вы можете сравнить его, если это действительно важно.

Для простого поддерживаемого кода я бы выбрал подход проверки таймера:

long endTime = System.currentTimeMillis() + 15000
while (System.currentTimeMillis() < endTime) {
  //loop
} 
1 голос
/ 03 сентября 2013

Вот мое предложение, и оно работает хорошо для меня :)

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;
}
1 голос
/ 05 апреля 2013

Вы можете использовать AOP и аннотацию @Timeable из jcabi-аспекты (я разработчик):

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

Когда будет достигнуто ограничение по времени, ваш поток получит флаг interrupted(), установленный на true, и ваша задача - правильно обработать эту ситуацию и остановить выполнение.

0 голосов
/ 19 января 2016

Я бы посоветовал вам сделать это с помощью класса timer, избегая Thread.sleep (xxx); способ.

например:

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);
    }
}
0 голосов
/ 09 января 2010

Решение, похожее на @Tom Hawtin, без размера произвольного цикла.

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

В этом случае размер внутреннего цикла начнется с малого, но увеличится в размере, если цикл будет особенно быстрым. Если он достаточно медленный, он может повторяться только один раз.

0 голосов
/ 08 января 2010

Для подхода java.util.concurrent см. Глава 6 Java-параллелизма на практике (раздел 6.3.7 Установка временных ограничений для задач, стр. 131).

Пример кода: Получение рекламы с временным бюджетом.

0 голосов
/ 08 января 2010

Никогда не проверяйте текущее время в замкнутом цикле.

В противном случае кто-то с ноутбуком может получить ожоги на коленях из-за перегрева процессора. Я слышал истории об этом на самом деле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...