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.

¿Fue útil?

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 proporcionar ThreadFactory ).
  • Las excepciones de tiempo de ejecución lanzadas en TimerTask eliminan ese hilo, lo que hace que Timer 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étodo afterExecute de ThreadPoolExecutor ). 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 () o ScheduledThreadPoolExecutor )
  • 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

  1. Timer no puede aprovechar los núcleos de CPU disponibles, a diferencia de ExecutorService , especialmente con múltiples tareas usando sabores de ExecutorService como ForkJoinPool
  2. 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 de Timer , no sería sencillo.
  3. 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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top