Concurrence - ExecutorService
Apprendre les pools de threads avec ExecutorService, Callable/Future et les patterns de graceful shutdown pour les services backend.
#java #concurrency #executor #futures
Pourquoi cette etape est importante
Creer des threads manuellement pour chaque tache ne passe pas a l'echelle.
ExecutorService apporte une concurrence controlee via des pools de threads.
Pools de threads
Utilise un pool pour reutiliser les threads et limiter la consommation de ressources.
ExecutorService pool = Executors.newFixedThreadPool(4);
Choix typiques :
- pool fixe pour charge stable
- pool cache pour pics de petites taches
- pool planifie pour jobs periodiques
Runnable vs Callable
Runnable: pas de resultatCallable<T>: retourne un resultat et peut lever des exceptions verifiees
Callable<Integer> task = () -> 21 * 2;
Future<Integer> future = pool.submit(task);
Integer value = future.get();
Bases de Future
Future permet de :
- attendre la fin (
get()) - verifier l'etat (
isDone()) - annuler (
cancel(true))
Evite de bloquer partout avec get() ; utilise des timeouts.
Integer value = future.get(1, TimeUnit.SECONDS);
Graceful shutdown
Toujours fermer les executors proprement.
pool.shutdown();
if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
pool.shutdownNow();
}
Cela evite les fuites de ressources et les arrets JVM bloques.
Erreurs frequentes
- ne jamais fermer le pool
- utiliser des pools non bornes en production
- bloquer longtemps dans des taches sans strategie de dimensionnement
- ignorer les exceptions des futures
Regle pratique
Utilise ExecutorService comme outil de concurrence bas niveau par defaut quand tu as besoin d'un controle explicite du pool.
A retenir
- Preferer les pools aux threads ad-hoc
- Utiliser
Callable/Futurepour les taches avec resultat - Mettre des timeouts sur les attentes bloquantes
- Toujours implementer un graceful shutdown