Java Timer vs ExecutorService?


263

Ho un codice in cui pianifico un'attività usando java.util.Timer. Mi guardavo intorno e ho visto che ExecutorServicepoteva fare lo stesso. Quindi questa domanda qui, hai usato Timere ExecutorServiceper pianificare le attività, qual è il vantaggio di uno che utilizza su un altro?

Volevo anche verificare se qualcuno avesse usato la Timerclasse e si fosse imbattuto in qualsiasi problema ExecutorServicerisolto per loro.


1
E se hai bisogno di qualcosa di ancora più ricco di funzionalità, dai un'occhiata al quarzo . Offre un controllo molto maggiore dei lavori, inclusi cron come la pianificazione, la pianificazione consapevole del cluster, il controllo individualizzato dei lavori (concetti come una corsa alla volta, dipendenze, ecc.). --Tim
Tim

Risposte:


313

Secondo Java Concurrency in Practice :

  • Timerpuò essere sensibile ai cambiamenti nell'orologio di sistema, ScheduledThreadPoolExecutorno.
  • Timerha solo un thread di esecuzione, quindi un'attività di lunga durata può ritardare altre attività. ScheduledThreadPoolExecutorpuò essere configurato con qualsiasi numero di thread. Inoltre, hai il pieno controllo sui thread creati, se lo desideri (fornendo ThreadFactory).
  • Le eccezioni di runtime lanciate TimerTaskuccidono quel thread, rendendo così Timermorto :-( ... cioè le attività pianificate non verranno più eseguite. ScheduledThreadExecutorNon solo rileva le eccezioni di runtime, ma consente di gestirle se lo si desidera (con il afterExecutemetodo di override da ThreadPoolExecutor). l'eccezione generata verrà annullata, ma altre attività continueranno a essere eseguite.

Se puoi usare ScheduledThreadExecutorinvece di Timer, fallo.

Un'altra cosa ... mentre ScheduledThreadExecutornon è disponibile nella libreria Java 1.4, esiste un backport di JSR 166 ( java.util.concurrent) su Java 1.2, 1.3, 1.4 , che ha la ScheduledThreadExecutorclasse.


63

Se è disponibile, è difficile pensare a un motivo per non utilizzare il framework degli esecutori Java 5. Calling:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();

ti darà una ScheduledExecutorServicefunzionalità simile a Timer(cioè sarà single-thread) ma il cui accesso potrebbe essere leggermente più scalabile (sotto il cofano, usa strutture simultanee piuttosto che una sincronizzazione completa come con la Timerclasse). L'uso di a ScheduledExecutorServiceti offre anche vantaggi come:

  • Puoi personalizzarlo se necessario (vedi la newScheduledThreadPoolExecutor()o la ScheduledThreadPoolExecutorclasse)
  • Le esecuzioni 'una tantum' possono restituire risultati

A proposito delle uniche ragioni per cui Timermi posso pensare sono:

  • È disponibile prima di Java 5
  • Una classe simile è fornita in J2ME, il che potrebbe rendere più semplice il porting della tua applicazione (ma in questo caso non sarebbe tremendamente difficile aggiungere un livello comune di astrazione)

1
Un altro motivo per l'utilizzo TimerTaskpotrebbe essere la disponibilità del scheduledExecutionTime()metodo che non sembra avere alcun equivalente in ScheduledExecutorService.
Rohit Agarwal,

3
Un'altra nota: sto scrivendo questo commento in 2k17, non c'è più J2ME. è già morto.
msangel

1
Java Timer-class è scadente.
JohnyTex,

26

ExecutorService è più recente e più generale. Un timer è solo un thread che esegue periodicamente cose che hai programmato per esso.

Un ExecutorService può essere un pool di thread o persino distribuito su altri sistemi in un cluster e fare cose come l'esecuzione in batch una tantum, ecc ...

Guarda cosa offrono ciascuno per decidere.



8

Dalla pagina della documentazione Oracle su ScheduledThreadPoolExecutor

Un ThreadPoolExecutor che può inoltre programmare comandi da eseguire dopo un determinato ritardo o da eseguire periodicamente. Questa classe è preferibile a Timer quando sono necessari più thread di lavoro o quando sono richieste la flessibilità o le capacità aggiuntive di ThreadPoolExecutor (che estende questa classe).

ExecutorService/ThreadPoolExecutoro ScheduledThreadPoolExecutorè una scelta ovvia quando si hanno più thread di lavoro.

Pro di ExecutorServiceoltreTimer

  1. Timernon è possibile trarre vantaggio dai core della CPU disponibili, a differenza, in ExecutorServiceparticolare, di più attività che utilizzano sapori ExecutorServicecome ForkJoinPool
  2. ExecutorServicefornisce API collaborative se è necessario il coordinamento tra più attività. Supponiamo di dover inviare un numero N di attività di lavoro e attendere il completamento di tutte. Puoi facilmente raggiungerlo con l' API invokeAll . Se si desidera ottenere lo stesso risultato con più Timerattività, non sarebbe semplice.
  3. ThreadPoolExecutor offre una migliore API per la gestione del ciclo di vita di Thread.

    I pool di thread risolvono due diversi problemi: in genere forniscono prestazioni migliorate quando si eseguono un gran numero di attività asincrone, a causa del ridotto sovraccarico di invocazione per attività e forniscono un mezzo per delimitare e gestire le risorse, inclusi i thread, consumate durante l'esecuzione di una raccolta di compiti. Ogni ThreadPoolExecutor mantiene anche alcune statistiche di base, come il numero di attività completate

    Pochi vantaggi:

    un. È possibile creare / gestire / controllare il ciclo di vita dei thread e ottimizzare i costi generali di creazione dei thread

    b. Puoi controllare l'elaborazione delle attività (Gestione furto, ForkJoinPool, invokeAll) ecc.

    c. È possibile monitorare l'avanzamento e lo stato dei thread

    d. Fornisce un migliore meccanismo di gestione delle eccezioni


5

Il motivo per cui a volte preferisco Timer rispetto a Executors.newSingleThreadScheduledExecutor () è che ottengo un codice molto più pulito quando ho bisogno del timer per essere eseguito sui thread demone.

confrontare

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

Lo faccio quando non ho bisogno della solidità di un servizio di esecutori.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.