Gérer proprement les interruptions de threads en Java

Voici la traduction rapide d’un article d’Alex Miller (avec son aimable permission naturellement), qui récapitule les grands principes de gestion de l’interruption des threads.
Un sujet souvent mal maîtrisé, qui pourtant, vous allez le voir, est relativement simple à comprendre.

Gestion des interruptions, par Alex Miller

Un thread Java ne peut pas être interrompu de manière préemptive. En revanche, une application peut appeler sa méthode Thread.interrupt(). Si le thread est en attente d’une opération bloquante à ce moment-là (comme wait, join ou sleep), une InterruptedException est levée. Dans le cas contraire, seul le flag interrupted du thread est activé.
Un thread recevant une InterruptedException a plusieurs options :

  • Gérer lui-même l’interruption. Le traitement typique consiste à vérifier si une condition particulière a été atteinte (si le thread doit s’arrêter ou changer d’état), et à modifier le comportement du thread en conséquence.
  • Propager l’exception. Celle-ci est immédiatement relancée, et sa gestion incombe alors à du code de plus haut niveau.
  • Retarder la gestion de l’exception. Il suffit pour cela d’appeler Thread.currentThread().interrupt() de manière à réactiver le flag d’interruption du thread. Du code de plus haut niveau peut alors vérifier l’état de ce flag et prendre les mesures adéquates.
  • Ignorer l’exception. L’exception est capturée et étouffée silencieusement. Cette solution est à proscrire – à moins naturellement que le bloc catch ne contienne tout le code nécessaire au traitement de l’interruption,auquel cas il ne s’agit que d’un cas particulier de la première option.

Réfléchissez soigneusement à la politique de gestion des interruptions de vos threads, et à leur réaction dans le cas où ils sont interrompus en pleine attente d’une opération bloquante. De manière générale, les frameworks techniques devraient propager les exceptions de manière transparente, et laisser les applications les gérer en accord avec la politique d’interruption de leurs threads.

En pratique

Voici un exemple de code gérant correctement l’interruption.
Le thread lancé effectue des boucles d’une seconde à l’aide de la méthode bloquante sleep(). L’utilisateur peut déclencher l’interruption de ce thread en saisissant quelquechose dans la console, et constater que la boucle s’est terminée prématurément.

  1. public class ThreadInterruption
  2. {
  3. public static void main(String[] args) throws Exception
  4. {
  5. // Démarrage du thread
  6. CounterThread counter = new CounterThread();
  7. counter.start();
  8. // Attente d’une interruption manuelle
  9. System.in.read();
  10. System.out.println(« Interruption ! »);
  11. counter.interrupt();
  12. // Attente de la fin du thread
  13. counter.join();
  14. }
  15. public static class CounterThread extends Thread
  16. {
  17. @Override
  18. public void run()
  19. {
  20. // Tant que le thread n’est pas interrompu…
  21. long time = 0L;
  22. while (! isInterrupted())
  23. {
  24. time = System.currentTimeMillis();
  25. try
  26. {
  27. // Une seconde d’attente
  28. Thread.sleep(1000);
  29. }
  30. catch (InterruptedException e)
  31. {
  32. System.out.println(« J’ai été interrompu ! »);
  33. // Activation du flag d’interruption
  34. Thread.currentThread().interrupt();
  35. }
  36. System.out.println(« Boucle de «  + (System.currentTimeMillis() – time) + « ms »);
  37. }
  38. }
  39. }
  40. }

Résultat :

 Début de la boucle, attente prévue 1000ms Fin de la boucle, attente réelle 1000ms Début de la boucle, attente prévue 1000ms Fin de la boucle, attente réelle 1000ms Début de la boucle, attente prévue 1000ms Fin de la boucle, attente réelle 1000ms Début de la boucle, attente prévue 1000ms <saisie dans la console> Interruption ! J'ai été interrompu ! Fin de la boucle, attente réelle 479ms

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

%d blogueurs aiment cette page :