Java : demarrer un Thread avec un timeout

Dans une application en client lourd, la manipulation des threads est une tâche courante : le thread dédié à l’affichage ne doit pas être bloqué par une action longue sous peine de provoquer les messages du style « ne répond pas ».

Mais pour autant, une tâche qui dure éternellement n’est pas envisageable. Dans certains cas, il peut être judicieux de définir un temps maximum d’exécution autorisé pour notre Thread. Si la tâche n’a pas répondue dans le temps imparti, elle est considérée comme perdue et elle doit être interrompue de force.

Je suis parti de ce post et cette question sur stackoverflow pour écrire cette classe :

  1. package fr.fluminis.thread;
  2.  
  3. import java.util.Timer;
  4. import java.util.TimerTask;
  5.  
  6. public class TimeOutThread extends Thread {
  7.  
  8.     // set as true to be a daemon thread and therefore exit on interrupt
  9.     Timer timer = new Timer(true);
  10.  
  11.     private final long timeout;
  12.  
  13.     private final TimeOutTask timeoutTask;
  14.  
  15.     /**
  16.      * Constructeur
  17.      *
  18.      * @param timeOutTask
  19.      * @param timeout
  20.      *            max execution time in milliseconds
  21.      */
  22.     public TimeOutThread(TimeOutTask timeOutTask, long timeout) {
  23.         this.timeoutTask = timeOutTask;
  24.         this.timeout = timeout;
  25.     }
  26.  
  27.     /**
  28.      * true if the thread has not ended.
  29.      */
  30.     boolean isRunning = true;
  31.  
  32.     /**
  33.      * true if all tasks where done.
  34.      */
  35.     private boolean everythingDone = false;
  36.  
  37.     /**
  38.      * if every thing could not be done, an {@link Exception} may have Happens.
  39.      */
  40.     Exception endedWithException = null;
  41.  
  42.     @Override
  43.     public void run() {
  44.         timer.schedule(new TimeOutTimer(Thread.currentThread()), timeout);
  45.         isRunning = true;
  46.         try {
  47.             timeoutTask.run();
  48.             setEverythingDone(true);
  49.         } catch (Exception e) {
  50.             endedWithException = e;
  51.         }
  52.     }
  53.  
  54.     public void setEverythingDone(boolean everythingDone) {
  55.         this.everythingDone = everythingDone;
  56.     }
  57.  
  58.     public boolean isEverythingDone() {
  59.         return everythingDone;
  60.     }
  61.  
  62.     public static interface TimeOutTask {
  63.         void run() throws Exception;
  64.     }
  65. }
  66.  
  67. /**
  68.  * Classe permettant de mettre fin au thread principal si le temps d'execution maximum est dépassé
  69.  */
  70. class TimeOutTimer extends TimerTask {
  71.     Thread t;
  72.  
  73.     TimeOutTimer(Thread t) {
  74.         this.t = t;
  75.     }
  76.  
  77.     @Override
  78.     public void run() {
  79.         if (t != null && t.isAlive()) {
  80.             t.interrupt();
  81.         }
  82.     }
  83. }

Et vous pouvez l’utiliser de la sorte :

  1.     public static void main(String args[]) {
  2.         long start = System.currentTimeMillis();
  3.         TimeOutThread myRunnable = new TimeOutThread(new TimeOutTask() {
  4.             public void run() {
  5.                 try {
  6.                     for (int i = 0; i < 100; i++) {
  7.                         System.out.println("doing something … " + i);
  8.                         // simulate a slow stream.
  9.  
  10.                         synchronized (this) {
  11.                             wait(10);
  12.                         }
  13.                         if (i == 3) {
  14.                             throw new RuntimeException("I am an exception");
  15.                         }
  16.                     }
  17.                 } catch (InterruptedException ie) {
  18.                     System.out.println("MyRunnable error…");
  19.                     ie.printStackTrace();
  20.                 }
  21.             }
  22.         }, 1000);
  23.         myRunnable.start();
  24.         try {
  25.             myRunnable.join();
  26.             long stop = System.currentTimeMillis();
  27.  
  28.             if (myRunnable.isEverythingDone())
  29.                 System.out.println("all done in " + (stop – start) + " ms.");
  30.             else {
  31.                 if (myRunnable.endedWithException != null) {
  32.                     System.out.println("End with exception in " + (stop – start) + " ms.");
  33.                     myRunnable.endedWithException.printStackTrace();
  34.                 } else {
  35.                     System.out.println("could not do everything in " + (stop – start) + " ms.");
  36.                 }
  37.             }
  38.         } catch (InterruptedException e) {
  39.             System.out.println("You've killed me!");
  40.         }
  41.         System.out.println("fin");
  42.     }

Le commentaires sont fermés.