Timer & TimerTask versus Thread + sleep en Java

102

Encontré preguntas similares hechas aquí, pero no hubo respuestas a mi satisfacción. Así que reformulando la pregunta de nuevo

Tengo una tarea que debe realizarse de forma periódica (por ejemplo, intervalos de 1 minuto). ¿Cuál es la ventaja de usar Timertask & Timer para hacer esto en lugar de crear un nuevo hilo que tiene un bucle infinito con el sueño?

Fragmento de código usando timertask-

TimerTask uploadCheckerTimerTask = new TimerTask(){

 public void run() {
  NewUploadServer.getInstance().checkAndUploadFiles();
 }
};

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(uploadCheckerTimerTask, 0, 60 * 1000);

Fragmento de código usando Thread y sleep-

Thread t = new Thread(){
 public void run() {
  while(true) {
   NewUploadServer.getInstance().checkAndUploadFiles();
   Thread.sleep(60 * 1000);
  }
 }
};
t.start();

Realmente no tengo que preocuparme si pierdo ciertos ciclos si la ejecución de la lógica toma más tiempo que el intervalo.

Por favor comente sobre esto ...

Actualización:
Recientemente encontré otra diferencia entre usar Timer versus Thread.sleep (). Suponga que la hora actual del sistema es las 11:00 a. M. Si revertimos la hora del sistema a las 10:00 a. M. Por alguna razón, el temporizador DEJARÁ de ejecutar la tarea hasta que llegue a las 11:00 a. M., Mientras que el método Thread.sleep () continuará ejecutando la tarea sin obstáculos. Este puede ser un factor importante a la hora de decidir qué utilizar entre estos dos.

Keshav
fuente
21
Punto de orden: Timer y TimerTask son obsoletos y han sido reemplazados efectivamente por ExecutorService, aunque su punto sigue en pie.
skaffman
Gracias por el consejo, decidí usar ExecutorService :)
Keshav
Gracias a todos por las respuestas, seguramente me dio más comprensión!
Keshav
6
El temporizador no está obsoleto y se prefiere cuando solo se necesita un hilo. ( java.sun.com/javase/6/docs/api/java/util/Timer.html )
Justin
2
Timer y TimerTask siguen siendo útiles en entornos JME donde ExecutorService no existe (desde JME Java 1.3 basado ...).
ス ー パ ー フ ァ ミ コ ン

Respuestas:

67

La ventaja de TimerTask es que expresa su intención mucho mejor (es decir, legibilidad del código) y ya tiene implementada la función cancel ().

Tenga en cuenta que se puede escribir en una forma más corta, así como su propio ejemplo:

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(
    new TimerTask() {
      public void run() { NewUploadServer.getInstance().checkAndUploadFiles(); }
    }, 0, 60 * 1000);
Zed
fuente
si el temporizador se usa para Todos los días, en 2 horas específicas a las 9 pm y 9 am, ... ¿cómo dar los valores? en el código de arriba ... @Zed?
gumuruh
12

Timer / TimerTask también tiene en cuenta el tiempo de ejecución de su tarea, por lo que será un poco más preciso. Y se ocupa mejor de los problemas de subprocesos múltiples (como evitar interbloqueos, etc.). Y, por supuesto, generalmente es mejor usar un código estándar bien probado en lugar de una solución casera.

MartinStettner
fuente
5

No sé por qué, pero un programa que estaba escribiendo usaba Timers y su tamaño de pila aumentaba constantemente, una vez que lo cambié a Thread / sleep problem resuelto.

Qandeel
fuente
9
El temporizador crea una cola de tareas que se actualiza continuamente. Cuando termine el temporizador, es posible que no se recolecte la basura inmediatamente. Por lo tanto, crear más temporizadores solo agrega más objetos al montón. Thread.sleep () solo pausa el hilo, por lo que la sobrecarga de memoria sería extremadamente baja.
Darryl Gerrow
4

Si obtiene una excepción y lo matan, eso es un problema. Pero TimerTask se encargará de ello. Se ejecutará independientemente de la falla en la ejecución anterior.

Popper de pila
fuente
4

De la Timer documentación :

Java 5.0 introdujo el paquete java.util.concurrent y una de las utilidades de concurrencia en él es ScheduledThreadPoolExecutor, que es un grupo de subprocesos para ejecutar tareas repetidamente a una velocidad o retraso determinados. Es efectivamente un reemplazo más versátil para la combinación Timer / TimerTask, ya que permite múltiples subprocesos de servicio, acepta varias unidades de tiempo y no requiere subclases de TimerTask (solo implemente Runnable). La configuración de ScheduledThreadPoolExecutor con un hilo lo hace equivalente a Timer.

Así que prefiero en ScheduledThreadExecutorlugar de Timer:

  • Timerutiliza un único hilo de fondo que se utiliza para ejecutar todas las tareas del temporizador, de forma secuencial. Por lo tanto, las tareas deben completarse rápidamente, de lo contrario, retrasará la ejecución de las tareas posteriores. Pero en caso de ScheduledThreadPoolExecutorque podamos configurar cualquier número de subprocesos y también podemos tener el control total proporcionando ThreadFactory.
  • Timerpuede ser sensible al reloj del sistema, ya que utiliza el Object.wait(long)método. Pero ScheduledThreadPoolExecutorno lo es.
  • Las excepciones de tiempo de ejecución lanzadas en TimerTask matarán ese hilo en particular, lo que hará que Timer muera donde podamos manejar eso ScheduledThreadPoolExecutorpara que las otras tareas no se vean afectadas.
  • Timerproporciona un cancelmétodo para finalizar el temporizador y descartar cualquier tarea programada, sin embargo, no interfiere con la tarea que se está ejecutando actualmente y deja que finalice. Pero si el temporizador se está ejecutando como un hilo de demonio, lo cancelemos o no, terminará tan pronto como todos los hilos del usuario terminen de ejecutarse.

Temporizador vs Thread.sleep

El temporizador hace uso Object.waity es diferente deThread.sleep

  1. Un waithilo en espera ( ) puede ser notificado (usando notify) por otro hilo, pero uno en espera no puede serlo, solo puede ser interrumpido.
  2. Una espera (y notificación) debe ocurrir en un bloque sincronizado en el objeto de monitor, mientras que la suspensión no ocurre.
  3. Mientras que dormir no libera el bloqueo, esperar liberará el bloqueo para el objeto al que se solicita la espera.
akhil_mittal
fuente
información muy útil. Además, el uso de Thread.sleep en un bucle infinito puede causar un alto uso de la CPU en pequeñas cantidades de retrasos.
Amir Fo
3

Hay un argumento crucial en contra de la gestión de esta tarea mediante hilos y sleepmétodos de Java . Estás usando while(true)permanecer indefinidamente en el bucle e hibernar el hilo poniéndolo a dormir. ¿Qué pasa si NewUploadServer.getInstance().checkAndUploadFiles();ocupa algunos recursos sincronizados? Otros subprocesos no podrán acceder a estos recursos, puede ocurrir una inanición que puede ralentizar toda la aplicación. Este tipo de errores son difíciles de diagnosticar y es una buena idea evitar su existencia.

El otro enfoque desencadena la ejecución del código que le importa, es decir, NewUploadServer.getInstance().checkAndUploadFiles();llamando al run()método de su TimerTaskmientras deja que otros hilos utilicen los recursos mientras tanto.

Boris Pavlović
fuente
16
No entiendo este argumento. Ambas opciones lanzan el mismo método desde un hilo, ambas opciones están durmiendo en un hilo mientras esperan para ejecutarse. No habrá diferencias de hambre entre las dos opciones.
satur9nine
2

Creo que entiendo tu problema, estoy viendo algo muy similar. Tengo temporizadores que son recurrentes, algunos cada 30 minutos y otros cada dos días. Por lo que leí y los comentarios que veo, parece que la recolección de basura nunca se ejecutará porque todas las tareas nunca se completan. Creo que la recolección de basura se ejecutaría cuando un temporizador está en suspensión, pero no lo veo y, según la documentación, no.

Creo que la generación de nuevos hilos se completa y permite la recolección de basura.

Alguien, por favor, demuestre que estoy equivocado, reescribir lo que heredé será un dolor.

Conocido
fuente