Вам понадобится Таймер .Взгляните на его методы ... Есть несколько из них, но их можно разделить на две категории: те, которые планируют с фиксированной задержкой (методы schedule(...
) и те, которые планируют с фиксированной скоростью (scheduleAtFixedRate(...
методы).
Фиксированная задержка - это то, что вы хотите, если вам требуется "плавность".Это означает, что время между выполнением задачи в основном постоянно.Это было бы то, что вам нужно для анимации в игре, и это нормально, если одно выполнение может немного отстать, пока средняя задержка составляет около вашего целевого времени.
Фиксированная скоростьэто то, что вы хотите, если вам требуется, чтобы выполнение задачи составляло общее время.Другими словами, среднее время по всем исполнениям должно быть постоянным.Если некоторые исполнения задерживаются, можно запустить несколько из них, чтобы «наверстать упущенное».Это отличается от фиксированной задержки, когда задача не будет запущена раньше, просто потому, что можно было «пропустить» ее реплику.
Я считаю, что фиксированная скорость - это то, что вам нужно.Поэтому вам нужно сначала создать новый Timer
.Тогда вам нужно вызвать метод scheduleAtFixedRate(TimerTask task, long delay, long period)
.Этот второй аргумент может быть 0, если вы хотите, чтобы таймер запускался немедленно.Третьим аргументом должно быть время между запусками задач.В вашем случае, если вы хотите, чтобы общее время составляло 1000 миллисекунд, это было бы 1000 / размер массива.Не размер массива / 1000, как вы.
Это оставляет нам первый аргумент: a TimerTask .Обратите внимание, что это абстрактный класс, для реализации которого требуется только метод run()
.Поэтому вам нужно создать подкласс и реализовать этот метод.Поскольку вы работаете над массивом, вам нужно будет передать этот массив в вашу реализацию через конструктор.Затем можно сохранить индекс того, какой элемент был обработан последним, и увеличивать его при каждом вызове run()
.По сути, вы заменяете цикл for методом run()
со счетчиком.Очевидно, вы больше не должны ничего делать, если счетчик достиг последнего элемента.В этом случае вы можете установить некоторый (логический) флаг в вашей реализации TimerTask, который указывает, что последний элемент был обработан.
После создания TimerTask и планирования его на Timer вам нужно будет подождать, пока TimerTaskфлаг, который будет установлен, указывая, что он сделал свою работу.Затем вы можете позвонить cancel()
на таймер, чтобы остановить его.В противном случае он будет продолжать вызывать бесполезные run()
методы для задачи.
Имейте в виду следующее: если работа, выполняемая в методе run()
, обычно занимает больше времени, чем интервал между двумя выполнениями, который в вашемСлучай будет около 2 миллисекунд, это не будет работать очень хорошо.Это имеет смысл только в том случае, если цикл for обычно занимает менее 1 секунды.Желательно гораздо меньше.
РЕДАКТИРОВАТЬ: о, также не будет работать хорошо, если размер массива слишком близко к пределу времени.Если вам нужно 1000 миллисекунд, и у вас есть 2000 элементов массива, в результате вы получите 0 для аргумента периода из-за округления.В этом случае вы можете запустить цикл for.
EDIT 2: а почему бы и нет ...
import java.util.Random;
import java.util.Timer;
public class LoopTest {
private final static long desiredTime = 1000;
public static void main(String[] args) {
final float[] input = new float[512];
final Random rand = new Random();
for(int i = 0; i < input.length; ++i) {
input[i] = rand.nextFloat();
}
final Timer timer = new Timer();
final LoopTask task = new LoopTask(input);
double interval = ((double)desiredTime/((double)input.length));
long period = (long)Math.ceil(interval);
final long t1 = System.currentTimeMillis();
timer.scheduleAtFixedRate(task, 0, period);
while(!task.isDone()) {
try {
Thread.sleep(50);
} catch(final InterruptedException i) {
//Meh
}
}
final long t2 = System.currentTimeMillis();
timer.cancel();
System.out.println("Ended up taking " + (t2 - t1) + " ms");
}
}
import java.util.TimerTask;
public class LoopTask extends TimerTask {
private final float[] input;
private int index = 0;
private boolean done = false;
public LoopTask(final float[] input) {
this.input = input;
}
@Override
public void run() {
if(index == input.length) {
done = true;
} else {
//TODO: actual processing goes here
System.out.println("Element " + index + ": " + input[index]);
++index;
}
}
public boolean isDone() {
return done;
}
}