2010-01-20 2 views
18

У меня есть один простой вопрос относительно Java TimerTask. Как приостановить/возобновить две задачи TimerTask на основе определенного условия? Например, у меня есть два таймера, которые работают между собой. Когда в задаче первого таймера выполняется определенное условие, первый таймер останавливается и запускает второй таймер, и то же самое происходит, когда определенное условие выполняется в задаче второго таймера. Класс ниже точно показывает, что я имею в виду:Приостановка/остановка и запуск/возобновление Java TimerTask непрерывно?

public class TimerTest { 
    Timer timer1; 
    Timer timer2; 
    volatile boolean a = false; 

    public TimerTest() { 
     timer1 = new Timer(); 
     timer2 = new Timer();  
    } 

    public void runStart() { 
     timer1.scheduleAtFixedRate(new Task1(), 0, 1000); 
    } 

    class Task1 extends TimerTask { 
     public void run() { 
      System.out.println("Checking a"); 
      a = SomeClass.getSomeStaticValue(); 

      if (a) { 
       // Pause/stop timer1, start/resume timer2 for 5 seconds 
       timer2.schedule(new Task2(), 5000); 
      } 
     } 
    } 

    class Task2 extends TimerTask{ 
     public void run() { 
      System.out.println("Checking a"); 
      a = SomeClass.getSomeStaticValue(); 

      if (!a) { 
       // Pause/stop timer2, back to timer1 
       timer1.scheduleAtFixedRate(new Task1(), 0, 1000); 
      } 

      // Do something... 
     } 
    } 

    public static void main(String args[]) { 
     TimerTest tt = new TimerTest(); 
     tt.runStart();  
    } 
} 

Так что мой вопрос, как я могу сделать паузу во время работы timer1timer2 и наоборот, а timer2 работает? Производительность и сроки - моя главная проблема, так как это необходимо реализовать в другом потоке. Кстати, я пытаюсь реализовать эти параллельные таймеры на Android.

Благодарим за помощь!

+0

Какое исключение? – cletus

+2

Исключение из потока "Timer-1" java.lang.IllegalStateException: Таймер уже отменен. – Faiz

+0

Возможно, вам стоит подумать о переходе к 'java.util.concurrent'. «Таймер» считается немного старой школой. –

ответ

24

TimerTask.cancel() От:

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

Таким образом, после его отмены он больше не будет запускаться снова. Вам лучше было бы использовать более современный ScheduledExecutorService (от Java 5+).

Edit: Основная конструкция является:

ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); 
exec.scheduleAtFixedRate(runnable, 0, 1000, TimeUnit.MILLISECONDS); 

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

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

В качестве альтернативы можно инкапсулировать каждую задачу как отдельный транзиторной службы:

final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); 
Runnable task1 = new Runnable() { 
    public void run() { 
    a++; 
    if (a == 3) { 
     exec.shutdown(); 
     exec = Executors.newSingleThreadScheduledExecutor(); 
     exec.scheduleAtFixedRate(task2, 0, 1000, TimeUnit.MILLISECONDS) 
    } 
    } 
}; 
exec.scheduleAtFixedRate(task1, 0, 1000, TimeUnit.MILLISECONDS); 
+1

Не могли бы вы показать мне, как реализовать «ScheduledExceutorService» в классе выше? спасибо – Faiz

+0

Это не самая лучшая идея закрыть службу-исполнитель, вы можете отменить задачу через ScheduledFuture, возвращаемую по расписаниюAtFixedRate() – axtavt

+0

@axtavt: 'cancel()' остановит задачу, уже запущенную – cletus

6

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

См. Это answer, он содержит видео и исходный код, как я сделал что-то подобное.

В основном есть два метода: pause и resume

В паузе:

public void pause() { 
    this.timer.cancel(); 
} 

В резюме:

public void resume() { 
    this.timer = new Timer(); 
    this.timer.schedule(aTask, 0, 1000); 
} 

Это делает восприятие паузы/резюме.

Если таймеры выполнять различные действия в зависимости от состояния приложения, которое вы можете рассматривать использовать StatePattern

Кулак определяют абстрактное состояние:

abstract class TaskState { 
    public void run(); 
    public TaskState next(); 
} 

и обеспечивают столько состояний, как вам нравится. Ключ в том, что одно государство ведет вас к другому.

class InitialState extends TaskState { 
    public void run() { 
     System.out.println("starting..."); 
    } 
    public TaskState next() { 
     return new FinalState(); 
    } 
} 
class FinalState extends TaskState { 
    public void run() { 
     System.out.println("Finishing..."); 
    } 
    public TaskState next(){ 
     return new InitialState(); 
    } 
} 

И затем вы меняете состояние в своем таймере.

Timer timer = new Timer(); 
TaskState state = new InitialState(); 

timer.schedule(new TimerTask() { 
    public void run() { 
      this.state.run(); 
      if(shouldChangeState()) { 
       this.state = this.state.next(); 
      } 
    } 
}, 0, 1000); 

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

+1

https://timingframework.dev.java.net/ Ссылка не сработала, пожалуйста, передумайте –

4

Просмотрите исходный код, вот изменения (которые в значительной степени подтверждают мои предыдущий ответ)

в task1:

// Stop timer1 and start timer2 
timer1.cancel(); 
timer2 = new Timer(); // <-- just insert this line 
timer2.scheduleAtFixedRate(new Task2(), 0, 1000); 

и tASK2:

// Stop timer2 and start timer1 
timer2.cancel(); 
timer1 = new Timer(); // <-- just insert this other 
timer1.scheduleAtFixedRate(new Task1(), 0, 1000); 

Она работает на моей машине:

it works! http://img687.imageshack.us/img687/9954/capturadepantalla201001m.png

+3

хороший фон в окне терминала :) –

+0

Nice, но что, если я хочу изменить период двух таймеров. Допустим, что период таймера 1 равен 5000, а таймер 2 - 1000, тогда я думаю, что это испортит весь код. В этом случае, как бы я мог это сделать –

4

На мой взгляд, это несколько заблуждаетесь. Если вашему коду нужны временные гарантии, вы не можете использовать Таймер в любом случае и не хотите. «Этот класс не предлагает гарантии в реальном времени: он планирует задачи с использованием метода Object.wait (long)».

Ответ, IMHO, заключается в том, что вы не хотите приостанавливать и перезапускать таймеры. Вы просто хотите подавить свои методы запуска от своего бизнеса. И это легко: вы просто заверните их в заявление if. Коммутатор включен, они работают, выключатель выключен, они пропускают этот цикл.

Редактировать: Вопрос существенно изменился из-за того, что изначально было, но я оставлю этот ответ на случай, если он поможет кому-либо. Я хочу сказать следующее: если вам неинтересно, когда ваше событие срабатывает в течение периода в миллисекундах (только то, что он не ПРЕВЫШАЕТСЯ один раз каждые N миллисекунд), вы можете просто использовать условные обозначения для методов запуска. Это, по сути, очень распространенный случай, особенно когда N меньше 1 секунды.

+0

В большинстве случаев это очень надежное и простое решение. +1 – Alex

13

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

timer.schedule(new TimerTask() { 
    public void run() { 
     if(!paused){ 
      //do your thing 
     } 
    } 
}, 0, 1000); 
+4

Я считаю, что это не эффективно. Таймер будет продолжать работать и проверять логическое значение каждый раз. – Alex

+0

Я сомневаюсь, что эффективность - это проблема, так как на практике в задаче, скорее всего, требуются более длительные операции, чем одно условие. Что касается меня в этом подходе, то задача может быть запущена в любое время после «возобновления». Это может быть заметно при длительных временных интервалах. – Jakob

0

Я могу остановить таймер и задачи, используя следующий код:

if(null != timer) 
    { 

     timer.cancel(); 
     Log.i(LOG_TAG,"Number of cancelled tasks purged: " + timer.purge()); 
     timer = null; 
    } 

    if(task != null) 
    { 
     Log.i(LOG_TAG,"Tracking cancellation status: " + task.cancel()); 
     task = null; 
    } 
2

Android не будет повторно использовать TimerTask, который уже был запланирован один раз. Таким образом, необходимо восстановить и Таймер и TimerTask, например, так в Фрагменте:

private Timer timer; 
private TimerTask timerTask; 

public void onResume() 
{ 
    super.onResume(); 

    timer = new Timer(); 
    timerTask = new MyTimerTask(); 
    timer.schedule(timerTask, 0, 1000); 
} 

public void onPause() 
{ 
    super.onPause(); 
    timer.cancel(); // Renders Timer unusable for further schedule() calls. 
} 
Смежные вопросы