Java Timer vs ExecutorService?

263

Tengo un código donde programo una tarea usando java.util.Timer. Estaba mirando alrededor y vi que ExecutorServicepodía hacer lo mismo. Entonces, esta pregunta aquí, ¿ha utilizado Timery ExecutorServicepara programar tareas, cuál es el beneficio de usar una sobre otra?

También quería comprobar si alguien había usado la Timerclase y se había encontrado con algún problema que los ExecutorServiceresolvió.

kal
fuente
1
Y si necesita algo aún más completo, vea el cuarzo . Le brinda mucho más control de trabajo, incluyendo cron como programación, programación con clúster, control individualizado sobre trabajos (conceptos como una ejecución a la vez, dependencias, etc.). --Tim
Tim

Respuestas:

313

De acuerdo con la concurrencia de Java en la práctica :

  • Timerpuede ser sensible a los cambios en el reloj del sistema, ScheduledThreadPoolExecutorno lo es.
  • Timertiene un solo hilo de ejecución, por lo que la tarea de ejecución prolongada puede retrasar otras tareas ScheduledThreadPoolExecutorse puede configurar con cualquier cantidad de hilos. Además, tiene control total sobre los hilos creados, si lo desea (al proporcionar ThreadFactory).
  • Las excepciones de tiempo de ejecución lanzadas TimerTaskeliminan ese hilo, por lo que Timermueren :-( ... es decir, las tareas programadas ya no se ejecutarán. ScheduledThreadExecutorNo solo captura las excepciones de tiempo de ejecución, sino que le permite manejarlas si lo desea (anulando el afterExecutemétodo desde ThreadPoolExecutor). La excepción lanzada se cancelará, pero otras tareas continuarán ejecutándose.

Si puede usar en ScheduledThreadExecutorlugar de Timerhacerlo, hágalo.

Una cosa más ... si bien ScheduledThreadExecutorno está disponible en la biblioteca Java 1.4, hay un Backport de JSR 166 ( java.util.concurrent) para Java 1.2, 1.3, 1.4 , que tiene la ScheduledThreadExecutorclase.

Peter Štibraný
fuente
63

Si está disponible para usted, entonces es difícil pensar en una razón para no usar el marco de ejecución de Java 5. Vocación:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();

le dará una ScheduledExecutorServicefuncionalidad similar a Timer(es decir, será de un solo subproceso) pero cuyo acceso puede ser un poco más escalable (bajo el capó, utiliza estructuras concurrentes en lugar de una sincronización completa como con la Timerclase). El uso de a ScheduledExecutorServicetambién le brinda ventajas tales como:

  • Puede personalizarlo si es necesario (ver el newScheduledThreadPoolExecutor()o la ScheduledThreadPoolExecutorclase)
  • Las ejecuciones 'únicas' pueden devolver resultados

Las únicas razones por las que Timerpuedo seguir son:

  • Está disponible antes de Java 5
  • Se proporciona una clase similar en J2ME, que podría facilitar la transferencia de su aplicación (pero en este caso no sería terriblemente difícil agregar una capa común de abstracción)
Neil Coffey
fuente
1
Otra razón para usar TimerTaskpuede ser la disponibilidad de un scheduledExecutionTime()método que no parece tener ningún equivalente ScheduledExecutorService.
Rohit Agarwal
3
Otra nota: estoy escribiendo este comentario en 2k17, no hay más J2ME. Ya está muerto.
msangel 01 de
1
Java Timer-class es horrible.
JohnyTex
26

ExecutorService es más nuevo y más general. Un temporizador es solo un hilo que ejecuta periódicamente cosas que ha programado para él.

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 únicos, etc.

Solo mira lo que cada uno ofrece para decidir.

Dustin
fuente
8

Desde la página de documentación de Oracle en ScheduledThreadPoolExecutor

Un ThreadPoolExecutor que además puede programar comandos para que se ejecuten después de un retraso determinado o para ejecutarse periódicamente. Esta clase es preferible a Timer cuando se necesitan múltiples subprocesos de trabajo, o cuando se requiere la flexibilidad o las capacidades adicionales de ThreadPoolExecutor (que esta clase extiende).

ExecutorService/ThreadPoolExecutoro ScheduledThreadPoolExecutores una opción obvia cuando tienes múltiples hilos de trabajo.

Pros de ExecutorServicemásTimer

  1. Timerno puede aprovechar los núcleos de CPU disponibles, a diferencia de ExecutorServicelas tareas múltiples que utilizan sabores ExecutorServicecomo ForkJoinPool
  2. ExecutorServiceproporciona API colaborativa si necesita coordinación entre múltiples tareas. Suponga que tiene que enviar un número N de tareas de trabajador y esperar a que se completen todas. Puede lograrlo fácilmente con invokeAll API. Si desea lograr lo mismo con múltiples Timertareas, no sería simple.
  3. ThreadPoolExecutor proporciona una mejor API para la gestión del ciclo de vida de Thread.

    Los grupos de subprocesos abordan dos problemas diferentes: generalmente proporcionan un rendimiento mejorado al ejecutar grandes cantidades de tareas asincrónicas, debido a la reducción de la sobrecarga de invocación por tarea, y proporcionan un medio para delimitar y administrar 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

    Pocas ventajas:

    a. Puede crear / gestionar / controlar el ciclo de vida de los subprocesos y optimizar los gastos generales de creación de subprocesos

    si. Puede controlar el procesamiento de tareas (Work Stealing, ForkJoinPool, invokeAll), etc.

    C. Puedes monitorear el progreso y la salud de los hilos

    re. Proporciona un mejor mecanismo de manejo de excepciones.

Ravindra babu
fuente
5

Mi razón para preferir a veces Timer en lugar de Executors.newSingleThreadScheduledExecutor () es que obtengo un código mucho más limpio cuando necesito que el temporizador se ejecute en hilos de demonio.

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.

Siamaster
fuente