Лучший способ запускать код в течение определенного периода времени

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

Текущий код;

// Calculate the new lines to draw 
            Timer timer3 = new Timer();
            timer3.schedule(new TimerTask(){
                public void run(){
                    ArrayList<String> Coords = new ArrayList<String>();
                    int x = Float.valueOf(lastFour[0]).intValue();
                    int y = Float.valueOf(lastFour[1]).intValue();
                    int x1 = Float.valueOf(lastFour[2]).intValue();
                    int y1 = Float.valueOf(lastFour[3]).intValue();
                    //Could be the wrong way round (x1,y1,x,y)?
                    Coords = CoordFiller.coordFillCalc(x, y, x1, y1);
                    String newCoOrds = "";
                    for (int j = 0; j < Coords.size(); j++)
                    {
                        newCoOrds += Coords.get(j) + " ";
                    }
                    newCoOrds.trim();
                    ClientStorage.storeAmmendedMotion(newCoOrds);

                }

            }
            ,time);

person mhollander38    schedule 09.02.2011    source источник


Ответы (4)


Если вы используете Java5 или более позднюю версию, обратите внимание на ScheduledThreadPoolExecutor< /a> и Future. С первым вы можете запланировать запуск задач после указанной задержки или через определенные промежутки времени, таким образом, он берет на себя роль Timer, только более надежно.

Средство Timer управляет выполнением отложенных (запуск этой задачи через 100 мс) и периодических (запуск этой задачи каждые 10 мс) задач. Однако у Timer есть некоторые недостатки, и ScheduledThreadPoolExecutor следует рассматривать как его замену. [...]

Timer создает только один поток для выполнения задач таймера. Если задача таймера выполняется слишком долго, точность синхронизации других TimerTask может пострадать. Если повторяющаяся задача TimerTask запланирована для запуска каждые 10 мс, а для выполнения другой TimerTask требуется 40 мс, повторяющаяся задача либо (в зависимости от того, была ли она запланирована с фиксированной скоростью или с фиксированной задержкой) вызывается четыре раза в быстрой последовательности после долго выполняющейся задачи. задача завершается или полностью пропускает четыре вызова. Запланированные пулы потоков устраняют это ограничение, позволяя вам предоставлять несколько потоков для выполнения отложенных и периодических задач.

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

Из Параллелизм Java на практике, раздел 6.2.5.

И Futures может быть ограничено выполнением максимум в течение указанного времени (выбрасывается TimeoutException, если он не может завершиться вовремя).

Обновлять

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

int totalTime = 50000; // in nanoseconds
long startTime = System.getNanoTime();
boolean toFinish = false;

while (!toFinish) 
{
    System.out.println("Task!");
    ...
    toFinish = (System.getNanoTime() - startTime >= totalTime);
}
person Péter Török    schedule 09.02.2011
comment
Спасибо, это выглядит полезным. Мне нужно, чтобы код выполнялся в течение установленного периода. ScheduledThreadPoolExecutor, по-видимому, может использовать только задержки и ожидания, а не выполнять задачу в течение определенного периода, аналогично Future в ожидании завершения выполнения. - person mhollander38; 10.02.2011
comment
@ mhollander38, насколько я понимаю, если вы позвоните, например, Future.get(1, TimeUnit.SECOND), через одну секунду выдаст TimeoutException и выполнение соответствующей задачи будет прекращено. Хотя я не проверял. - person Péter Török; 10.02.2011
comment
@ mhollander38, я добавил еще одно решение, улучшив код в вашем (теперь удаленном) репосте. - person Péter Török; 10.02.2011
comment
теперь реализовал это, и это делает свое дело. Большое спасибо, Питер. - person mhollander38; 10.02.2011
comment
@Péter Török Тайм-аут во время вызова Future.get(1, TimeUnit.SECOND) вообще не влияет на основную задачу. Нетерпеливый абонент получает TimeoutException, так что он может делать что-то еще, но это все. - person maaartinus; 20.06.2012

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

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

Нет простого способа решить эту проблему без тесного сотрудничества с исполняемой задачей. Лучший способ — позволить задаче контролировать свое выполнение и убедиться, что она возвращается (завершается), когда ее время истекло.

person aioobe    schedule 09.02.2011
comment
+1, несмотря на ссылку Thread.stop(), которая должна иметь теги <blink> вокруг гигантского предупреждения о том, что это ни при каких обстоятельствах не является правильным подходом к любой проблеме со стороны того, кому нужно спросить о выполнении таймера. Если задача должна выполняться в течение заранее определенного промежутка времени, вам нужно сообщить задаче об этом и позволить ей выполнять самоконтроль, как предлагает @aioobe. - person andersoj; 10.02.2011

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

Сотрите это, если под остановкой вы подразумеваете просто остановку обработки.

person biziclop    schedule 09.02.2011

Следует также отметить, что обычно вам нужно создать только один Timer(). Из фрагмента кода я предполагаю, что вы создаете несколько объектов Timer().

Время в методе расписания — это время запуска, а не продолжительность выполнения.

Подумайте о том, чтобы поставить время начала перед циклом for и поставить перерыв в цикле for, если вы превысили лимит времени.

long startedAt = System.currentTimeMillis();
long finishedCorrectly = true;
for (int j = 0; j < Coords.size(); j++) {
  newCoOrds += Coords.get(j) + " ";
  if ((System.currentTimeMillis() - startedAt) > MAX_TIME_TO_RUN) {
    finishedCorrectly = false;
    break;
  }
}
person MrJacqes    schedule 09.02.2011