Цикл Java на определенную продолжительность - PullRequest
11 голосов
/ 31 марта 2010

Есть ли способ, которым я могу легко сделать цикл for в течение определенного времени? (не измеряя время самостоятельно, используя System.currentTimeMillis ()?)

т.е. Я хочу сделать что-то подобное в Java:

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

Спасибо

Ответы [ 8 ]

24 голосов
/ 31 марта 2010

Нет, не существует встроенной конструкции, которая делает это.

Я хочу указать, что вы не должны использовать System.currentTimeMillis () для выполнения или задержки задачи на определенный период времени. Вместо этого используйте System.nanoTime (). Первый метод является неточным в Windows, а второй - точным независимо от ОС. Вы можете использовать перечисление TimeUnit, чтобы легко переходить между временем в миллисекундах или любой другой единицей времени, временем в наносекундах.

for (long stop=System.nanoTime()+TimeUnit.SECONDS.toNanos(2);stop>System.nanoTime();) {
  /*
   * Hammer the JVM with junk
   */
}
10 голосов
/ 31 марта 2010

Я думаю, что это то, что вы хотите:

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

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

РЕДАКТИРОВАТЬ

На самом деле нет сейфа альтернативы опросу часов или опроса флага. Теоретически, вы можете изменить приведенный выше фрагмент так, чтобы он вызывал устаревший метод Thread.stop() вместо Thread.interrupt().

НЕ рекомендую использовать Thread.stop() и друзей. Они несовершенны и опасны в использовании. Я просто представляю это как теоретическую альтернативу.)

РЕДАКТИРОВАТЬ 2

Просто отметим, что использование Thread.interrupt() имеет преимущества перед установкой общего флага:

  • Thread.interrupt () приведет к тому, что определенные блокирующие операции ввода-вывода и методы синхронизации будут разблокированы и выдано проверенное исключение. Обновление общего флага не сделает этого.

  • Некоторые сторонние библиотеки также проверяют флаг прерывания, чтобы увидеть, должны ли они прекратить то, что они делают в настоящее время.

  • Если ваш цикл включает в себя вызовы других методов и т. Д., Thread.interrupt () означает, что вам не нужно беспокоиться о том, что эти методы могут получить доступ к флагу ... если это необходимо.

РЕДАКТИРОВАТЬ 3

Просто добавим, что sleep(N) не гарантирует пробуждение спящего потока через ровно N миллисекунды. Но при нормальных обстоятельствах это будет достаточно близко.

3 голосов
/ 10 мая 2011

Я сделал простую, но отстойную реализацию этой проблемы. Я хотел избежать Timer и TimeTask и в итоге получил это решение для быстрого исправления.

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

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 голос
/ 31 марта 2010

Вот еще одно предложение: <pre> public class TimerLoop { private final AtomicBoolean loop = new AtomicBoolean();</p> <pre><code>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(); } }

}

Метод выполняет метод run() предоставленного Runnable несколько раз, пока не истечет таймер.

Соображения:

  • Время будет приблизительным.
  • Будьте осторожны при реализации метода run(), так как он потенциально потребляет всю мощность вашего процессора.
  • Реализация не является поточно-ориентированной, если вы не создадите новый экземпляр класса TimerLoop для каждого Runnable, который вы хотели бы выполнить.
1 голос
/ 31 марта 2010

Нет. Это своего рода странный запрос, учитывая, насколько просто было бы просто написать функцию, которая использует System.currentTimeMillis () (или какую бы функцию времени вы ни выбрали). Больше контекста ситуации может быть в порядке.

0 голосов
/ 31 марта 2010

Циклы повторяются по сравнению значений, а не по продолжительности. Поэтому, если вы сами не назначите и не сравните системное время, вы не сможете этого сделать. Однако, если вы хотите, чтобы он был интуитивно понятным, тогда вы можете иметь функцию, которая внутренне использует миллисекунды, но принимает в качестве аргумента минуты и использует ее.

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

0 голосов
/ 31 марта 2010

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

Thread thread = Thread.currentThread();
thread.sleep(10);      // 10 milliseconds
thread.sleep(12, 345); // 12 milliseconds and 345 nanoseconds.
0 голосов
/ 31 марта 2010

Я не думаю, что есть способ зацикливаться в течение определенного периода времени, не проверяя, зациклен ли вы в течение определенного периода времени.

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