Ho il codice in cui pianifico un’attività utilizzando java.util.timer
. Stavo guardando in giro e ho visto ExecutorService
può fare lo stesso. Quindi, questa domanda qui, hai usato Timer ed ExecutorService
per pianificare i compiti, qual è il vantaggio di uno che usa su un altro?
Volevo anche verificare se qualcuno avesse usato la class Timer
e si fosse imbattuto in qualsiasi problema risolto da ExecutorService
.
Secondo Java Concurrency in Practice :
Timer
può essere sensibile alle modifiche dell’orologio di sistema, ScheduledThreadPoolExecutor
no. Timer
ha un solo thread di esecuzione, quindi un’attività a esecuzione prolungata può ritardare altre attività. ScheduledThreadPoolExecutor
può essere configurato con qualsiasi numero di thread. Inoltre, hai il pieno controllo sui thread creati, se lo desideri (fornendo ThreadFactory
). TimerTask
quel thread, rendendo quindi Timer
morto 🙁 … cioè le attività pianificate non verranno più eseguite. ScheduledThreadExecutor
non afterExecute
solo eccezioni di runtime, ma consente di gestirle se lo si desidera (ignorando il metodo afterExecute
da ThreadPoolExecutor
). L’attività che ha ThreadPoolExecutor
un’eccezione verrà annullata, ma altre attività continueranno a essere eseguite. Se è ansible utilizzare ScheduledThreadExecutor
anziché Timer
, farlo.
Un’altra cosa … mentre ScheduledThreadExecutor
non è disponibile nella libreria Java 1.4, esiste un backport di JSR 166 ( java.util.concurrent
) in Java 1.2, 1.3, 1.4 , che ha la class ScheduledThreadExecutor
.
Se è disponibile, è difficile pensare a un motivo per non utilizzare il framework per esecutori Java 5. Calling:
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
ti darà un servizio ScheduledExecutorService
con funzionalità simili a Timer
(cioè sarà a thread singolo) ma il cui accesso potrebbe essere leggermente più scalabile (sotto la cappa, utilizza strutture concorrenti piuttosto che la sincronizzazione completa come con la class Timer
). L’utilizzo di ScheduledExecutorService
offre anche vantaggi quali:
newScheduledThreadPoolExecutor()
o la class ScheduledThreadPoolExecutor
) Circa le uniche ragioni per attenersi a Timer
posso pensare sono:
ExecutorService è più recente e più generale. Un timer è solo un thread che esegue periodicamente roba che hai programmato per esso.
Un ExecutorService può essere un pool di thread, o anche distribuito su altri sistemi in un cluster e fare cose come l’esecuzione in batch una tantum, ecc …
Basta guardare ciò che ognuno offre per decidere.
Ecco alcune buone pratiche sull’utilizzo di Timer:
http://tech.puredanger.com/2008/09/22/timer-rules/
In generale, userei Timer per cose veloci e sporche ed Executor per un uso più robusto.
La ragione per cui a volte preferisco il Timer su Executors.newSingleThreadScheduledExecutor () è che ottengo un codice molto più pulito quando ho bisogno che il timer esegua su thread daemon.
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 robustezza di un servizio executors.
Dalla pagina di documentazione di Oracle su ScheduledThreadPoolExecutor
Un ThreadPoolExecutor che può inoltre programmare i comandi da eseguire dopo un determinato ritardo o da eseguire periodicamente. Questa class è preferibile a Timer quando sono necessari più thread di lavoro o quando sono richieste la flessibilità o le funzionalità aggiuntive di ThreadPoolExecutor (che questa class estende).
ExecutorService/ThreadPoolExecutor
o ScheduledThreadPoolExecutor
è una scelta ovvia quando si hanno più thread di lavoro.
Professionisti di ExecutorService
over Timer
Timer
non può sfruttare i core CPU disponibili a differenza di ExecutorService
particolare con più attività che utilizzano i sapori di ExecutorService
come ForkJoinPool ExecutorService
fornisce API collaborative se è necessario il coordinamento tra più attività. Supponete di dover inviare N numero di compiti di lavoro e attendere il completamento di tutti loro. Puoi facilmente ottenerlo con invokeAll API. Se si desidera ottenere lo stesso con più attività del Timer
, non sarebbe semplice. ThreadPoolExecutor fornisce API migliori per la gestione del ciclo di vita dei thread.
I pool di thread risolvono due problemi diversi: in genere forniscono prestazioni migliori durante l’esecuzione di un numero elevato di attività asincrone, a causa di un sovraccarico di chiamata per attività ridotto e forniscono un mezzo per limitare e gestire le risorse, inclusi i thread, consumati 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. È ansible creare / gestire / controllare il ciclo di vita dei thread e ottimizzare i costi generali di creazione dei thread
b. È ansible controllare l’elaborazione delle attività (Work Stealing, ForkJoinPool, invokeAll) ecc.
c. È ansible monitorare lo stato di avanzamento e la salute dei thread
d. Fornisce un migliore meccanismo di gestione delle eccezioni