Pausar/detener e iniciar/reanudar Java TimerTask continuamente?

Tengo una simple pregunta con respecto a Java TimerTask. ¿Cómo puedo poner en pausa/reanudar dos TimerTask tareas basadas en una cierta condición? Por ejemplo yo tengo dos temporizadores que se ejecutan entre uno y otro. Cuando una determinada condición se ha cumplido dentro de la tarea de primer contador de tiempo, el primer temporizador se detiene y se inicia el cronómetro de segundos, y lo mismo sucede cuando una determinada condición se ha cumplido dentro de la tarea de segundo temporizador. La clase de abajo muestra exactamente lo que quiero decir:

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

Así que mi pregunta es, ¿cómo hago una pausa timer1 mientras se ejecuta timer2 y viceversa, mientras que timer2 se está ejecutando? El rendimiento y el tiempo es mi principal preocupación, ya que este debe ser implementado dentro de otro subproceso en ejecución. Por la manera en que yo estoy tratando de implementar estos concurrentes temporizadores en Android.

Gracias por su ayuda!

  • Excepción en el hilo «Temporizador de 1» de java.lang.IllegalStateException: Temporizador ya cancelado.
  • Usted puede ser que desee pensar acerca de cómo mover a java.util.concurrent. Timer se considera un poco de la vieja escuela.
  • He editado de parar/reiniciar para pausar/reanudar la temporizadores. Es posible que el uso de Thread.sleep(milliseconds)?
  • Me doy cuenta de que esto es sólo el código de ejemplo y estás en cosas más grandes. Pero en este ejemplo, no se usan dos temporizadores, pero uno, con una adecuada si las condiciones de dictar lo que el comportamiento para hacer dentro del método run. Muchas veces uno piensa que en muchos de los temporizadores y muchos TimerTasks, cuando sólo necesitas que si tienes algún tipo de periodicidad que requiere (uno es de 20 ms, el otro es cada 2 minutos). Incluso en ese caso, yo no la pausa, como digo en mi respuesta. Me acaba de cambiar lo que el método de ejecución no. A menos, claro, que estamos haciendo algo que es sensible al tiempo (por ejemplo, la ejecución de un cronógrafo).
  • Tom Hawtin, ¿cómo se Temporizador de la vieja escuela? He visto a la gente lucha con hilo basado en conceptos para resolver en tiempo real de los problemas que se pueden resolver fácilmente con temporizadores. Temporizador está vivo y bien, y los hilos son ideales para operaciones de roscado.
  • Quiero realizar dos tareas diferentes según condición única en la diferente velocidad del tiempo. Por ejemplo, digamos que timer1 cheques a por cada segundo y si a es cierto, entonces timer2 comienza a realizar durante 5 segundos, se detiene y continúa revisando a por cada segundo.
  • He re-editado de nuevo el código de cerca mostrar exactamente lo que yo estoy tratando de hacer. Lo siento por la confusión!
  • esto es claro. Mi punto era que, incluso con diferentes periodicidades — 5 segundos y 2 segundos-me acaba de programar dos de tasa fija las tareas en un temporizador. A menos que sea absolutamente crucial que los otros temporizador empieza a contar los segundos DESDE el momento en QUE se enciende. Si no, usted acaba de mantener las tareas en ejecución y sólo modifican sus métodos.

InformationsquelleAutor Faiz | 2010-01-20

8 Kommentare

  1. 25

    De TimerTask.cancelar():

    Tenga en cuenta que la llamada a este método de
    dentro del método run de la repetición de una
    temporizador tarea absolutamente garantiza que
    el temporizador de la tarea no se ejecutará de nuevo.

    Así que una vez cancelado, no correr de nuevo. Usted sería mejor que en lugar de utilizar la más moderna ScheduledExecutorService (a partir de Java 5+).

    Edición: El básico de construcción es:

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

    pero buscando en él no hay forma de cancelar la tarea una vez que se inicia sin necesidad de apagar el servicio, que es un poco extraño.

    TimerTask podría ser más fácil en este caso, pero usted tendrá que crear una nueva instancia al comenzar uno. No puede ser reutilizado.

    Alternativamente, usted puede encapsular cada tarea por separado como una transitoria servicio:

    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);
    • ¿Podrías mostrarme cómo implementar el ScheduledExceutorService en la clase anterior? gracias
    • No es la mejor idea para apagar el ejecutor de servicio, usted puede cancelar una tarea a través de ScheduledFuture devuelto por scheduleAtFixedRate()
    • cancel(false) no
  2. 15

    solución más sencilla que he encontrado: sólo hay que añadir un valor booleano en la ejecución de código en el temporizador de la tarea, así:

    timer.schedule( new TimerTask() {
        public void run() {
           if(!paused){
               //do your thing
           }
        }
     }, 0, 1000 );
    • Creo que esto no es eficiente. Temporizador de mantener en funcionamiento y comprobación de valor booleano cada vez.
    • Dudo de la eficiencia es una preocupación, ya que en la práctica es probable que haya más operaciones en la tarea de una sola condicional. Lo que me preocupa de este enfoque es la tarea puede disparar en cualquier momento después de ser «reanudación». Esto podría ser notable por largos intervalos de tiempo.
    • esto puede servir al propósito, pero un poco molesto en la solución , más bien, si podemos hacer el seguimiento de este proceso y , poner en pausa y reanudar la demanda va a ser bueno
  3. 7

    Si usted ya ha cancelado un temporizador, no se puede volver a empezar, tendrás que crear una nueva.

    Ver este respuesta, contiene un video y el código fuente de cómo hice algo similar.

    Básicamente hay dos métodos: pause y resume

    En pausa:

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

    En resumen:

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

    Que hace que la percepción de pausa/reanudar.

    Si su temporizadores realizar diferentes acciones basadas en el estado de la aplicación, usted puede considerar el uso de la StatePattern

    Puño definir un estado abstracto:

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

    Y proporcionar muchos estados, como te gusta. La clave está en que un estado lleva a la otra.

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

    Y, a continuación, cambie el estado en su temporizador.

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

    Por último, si lo que necesitas es hacer la misma cosa, pero en proporciones diferentes, usted puede considerar el uso de la TimingFramework. Es un poco más complejo, pero vamos a hacerlo fresco animaciones, permitiendo que la pintura de ciertos componentes tienen lugar a diferentes tasas ( en lugar de ser lineal )

  4. 4

    En mi opinión, esto es algo equivocado. Si su código de necesidades garantías del tiempo, usted no puede utilizar el Temporizador de todos modos, ni desea. «Esta clase no ofrece en tiempo real garantiza: que los horarios de tareas utilizando el Objeto.wait(long) método.»

    La respuesta, en mi humilde opinión, es que usted no desea hacer una pausa y reiniciar el temporizadores. Usted sólo quiere suprimir sus métodos de hacer su negocio. Y eso es fácil: sólo se envuelven en un if declaración. El interruptor está activado, se ejecuta, el interruptor está apagado, se olvida de ese ciclo.

    Edición: La pregunta ha cambiado sustancialmente de lo que era originalmente, pero voy a dejar esta respuesta en caso de que ayuda a nadie. Mi punto es: si no te importa cuando en su evento de incendios en el N milésima de segundo lapso (sólo que no se SUPERAN una vez cada N milisegundos), usted puede utilizar condicionales en la ejecución de los métodos. Este es, de hecho, un caso muy común, especialmente cuando N es menor que 1 segundo.

    • En la mayoría de los casos, esta es una muy fiable y sencilla solución. +1
  5. 4

    La revisión de su código fuente, aquí están los cambios ( que bastante validar mi respuesta anterior )

    En tarea1:

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

    y en tarea2:

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

    Funciona en mi máquina:

    Pausar/detener e iniciar/reanudar Java TimerTask continuamente?

    • bonito fondo en la ventana de terminal 🙂
    • Bueno, pero ¿Qué pasa si quiero cambiar el período de dos temporizadores. Digamos que el período de timer 1 es de 5000 y timer 2 es de 1000, entonces supongo que esto tornillo de seguridad de todo el código. En ese caso, ¿cómo iba yo a ser capaz de hacerlo
  6. 3

    Android no reutilizar una TimerTask que ya se ha programado una vez. Por tanto, es necesario crear una nueva instancia, tanto el Temporizador y TimerTask, por ejemplo como este en un Fragmento:

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

    Soy capaz de detener un temporizador y una tarea usando el siguiente código:

        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;
        }
  8. 0
        Timer timer1;
        private boolean videoCompleteCDR=false;
        private boolean isVideoPlaying=false;   
        int videoTime=0;
        private int DEFAULT_VIDEO_PLAY_TIME = 30;  
    
        @Override
        public View onCreate(){
           isVideoPlaying = true; //when server response is successfully
        }
    
    
        @Override
        public void onPause() {
            super.onPause();
    
            if(isVideoPlaying ) {
                if(this.timer1 !=null) {
                    this.timer1.cancel();
                }
            }
        }
        @Override
        public void onResume() {
            super.onResume();
            if(isVideoPlaying  && !videoCompleteCDR) {
                callTimerTask();
            }
        }
    
        @Override
        public void onHiddenChanged(boolean hidden) {
            super.onHiddenChanged(hidden);
            if (!hidden) {
                printLog( "GameFragment  visible ");
                if(isVideoPlaying  && !videoCompleteCDR) {
                    callTimerTask();
                }
    
            } else {
                printLog("GameFragment in visible ");
                if(isVideoPlaying) {
                    if(this.timer1 !=null) {
                        this.timer1.cancel();
                    }
                }
            }
        }
    
        private void callTimerTask() {
            //TODO Timer for auto sliding
            printLog( "callTimerTask Start" );
            timer1 = new Timer();
            timer1.schedule(new TimerTask() {
                @Override
                public void run() {
                    if (getActivity() != null) {
                        getActivity().runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                if (getActivity() == null) {
                                    return;
                                }
                                videoTime++;
                                if(DEFAULT_VIDEO_PLAY_TIME ==videoTime){
                                    videoCompleteCDR=true;
                                    Log.e("KeshavTimer", "callTimerTask videoCompleteCDR called.... " +videoTime);
                                    destroyTimer();
                                }
                                Log.e("KeshavTimer", "callTimerTask videoTime " +videoTime);
                            }
                        });
                    } else {
                        printLog("callTimerTask getActivity is null ");
                    }
                }
            }, 1000, 1000);
            //TODO  300, 2000;
        }
    
    
        private void destroyTimer(){
            this.timer1.cancel();
        }

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea