Java Timer vs ExecutorService?
-
03-07-2019 - |
Pregunta
Tengo un código donde programo una tarea usando java.util.timer
. Miré a mi alrededor y vi que ExecutorService
puede hacer lo mismo. Entonces, esta pregunta aquí, ¿ha usado Timer y ExecutorService
para programar tareas, cuál es el beneficio de usar una sobre otra?
También quería comprobar si alguien había usado la clase Timer
y se había encontrado con algún problema que el ExecutorService
resolviera para ellos.
Solución
Según Java Concurrency in Practice :
-
Timer
puede ser sensible a los cambios en el reloj del sistema,ScheduledThreadPoolExecutor
no lo es. -
Timer
tiene solo un hilo de ejecución, por lo que una tarea de larga ejecución puede retrasar otras tareas.ScheduledThreadPoolExecutor
se puede configurar con cualquier número de subprocesos. Además, tiene control total sobre los subprocesos creados, si lo desea (al proporcionarThreadFactory
). - Las excepciones de tiempo de ejecución lanzadas en
TimerTask
eliminan ese hilo, lo que hace queTimer
sea muerto :-( ... es decir, las tareas programadas no se ejecutarán más.ScheduledThreadExecutor
no solo captura las excepciones de tiempo de ejecución, sino que le permite manejarlas si lo desea (al anular el métodoafterExecute
deThreadPoolExecutor
). La tarea que produjo la excepción se cancelará, pero otras tareas continuarán ejecutándose.
Si puede usar ScheduledThreadExecutor
en lugar de Timer
, hágalo.
Una cosa más ... mientras que ScheduledThreadExecutor
no está disponible en la biblioteca Java 1.4, hay un Backport de JSR 166 ( java.util.concurrent
) a Java 1.2, 1.3, 1.4 , que tiene la clase ScheduledThreadExecutor
.
Otros consejos
Si está disponible para usted, entonces es difícil pensar en una razón no para usar el framework de ejecutores Java 5. Llamando:
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
le dará un ScheduledExecutorService
con funcionalidad similar a Timer
(es decir, será de un solo hilo) pero cuyo acceso puede ser ligeramente más escalable (bajo el capó, utiliza estructuras concurrentes en lugar de la sincronización completa como con la clase Timer
). El uso de ScheduledExecutorService
también le ofrece ventajas como:
- Puede personalizarlo si es necesario (consulte la clase
newScheduledThreadPoolExecutor ()
oScheduledThreadPoolExecutor
) - Las ejecuciones 'one off' pueden devolver resultados
Acerca de las únicas razones para seguir el Timer
que se me ocurre:
- Está disponible pre Java 5
- En J2ME se proporciona una clase similar, lo que podría facilitar la portabilidad de la aplicación (pero en este caso no sería muy difícil agregar una capa de abstracción común)
ExecutorService es más nuevo y más general. Un temporizador es solo un hilo que periódicamente ejecuta cosas que has programado para ello.
Un ExecutorService puede ser un grupo de subprocesos, o incluso extenderse a través de otros sistemas en un clúster y hacer cosas como la ejecución de lotes de una sola vez, etc ...
Solo mire lo que cada uno ofrece para decidir.
Aquí hay algunas otras buenas prácticas sobre el uso del temporizador:
http://tech.puredanger.com/2008/09/22 / timer-rules /
En general, usaría Timer para cosas rápidas y sucias y Executor para un uso más robusto.
Mi razón para preferir a veces Timer en vez de Executors.newSingleThreadScheduledExecutor () es que obtengo un código mucho más limpio cuando necesito que el temporizador se ejecute en los hilos del daemon.
comparar
private final ThreadFactory threadFactory = new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
};
private final ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor(threadFactory);
con
private final Timer timer = new Timer(true);
Hago esto cuando no necesito la solidez de un servicio de ejecución.
De la página de documentación de Oracle en ScheduledThreadPoolExecutor
Un ThreadPoolExecutor que adicionalmente puede programar comandos para que se ejecuten después de un retraso determinado, o para que se ejecuten periódicamente. Esta clase es preferible a Temporizador cuando se necesitan múltiples subprocesos de trabajo, o cuando se requiere la flexibilidad o capacidades adicionales de ThreadPoolExecutor (que se extiende esta clase).
ExecutorService / ThreadPoolExecutor
o ScheduledThreadPoolExecutor
es una opción obvia cuando tiene varios subprocesos de trabajo.
Ventajas de ExecutorService
sobre Timer
-
Timer
no puede aprovechar los núcleos de CPU disponibles, a diferencia deExecutorService
, especialmente con múltiples tareas usando sabores deExecutorService
como ForkJoinPool -
ExecutorService
proporciona API de colaboración si necesita coordinación entre varias tareas. Supongamos que tiene que enviar N número de tareas de trabajo y esperar a que se completen todas. Puede lograrlo fácilmente con invokeAll API. Si desea lograr lo mismo con varias tareas deTimer
, no sería sencillo. -
ThreadPoolExecutor proporciona una mejor API para la gestión del ciclo de vida de Thread.
Los grupos de subprocesos resuelven dos problemas diferentes: generalmente proporcionan un rendimiento mejorado al ejecutar grandes cantidades de tareas asíncronas, debido a la reducción de la sobrecarga de invocación por tarea, y proporcionan un medio de delimitación y administración de los recursos, incluidos los subprocesos, consumidos al ejecutar Una colección de tareas. Cada ThreadPoolExecutor también mantiene algunas estadísticas básicas, como el número de tareas completadas
Algunas ventajas:
a. Puede crear / administrar / controlar el ciclo de vida de Threads & amp; optimizar los gastos generales de creación de hilos
b. Puede controlar el procesamiento de tareas (Work Stealing, ForkJoinPool, invokeAll) etc.
c. Puedes monitorear el progreso y la salud de los hilos
d. Proporciona un mejor mecanismo de manejo de excepciones