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 :
-
package fr.fluminis.thread;
-
-
import java.util.Timer;
-
import java.util.TimerTask;
-
-
public class TimeOutThread extends Thread {
-
-
// set as true to be a daemon thread and therefore exit on interrupt
-
Timer timer = new Timer(true);
-
-
private final long timeout;
-
-
private final TimeOutTask timeoutTask;
-
-
/**
-
* Constructeur
-
*
-
* @param timeOutTask
-
* @param timeout
-
* max execution time in milliseconds
-
*/
-
public TimeOutThread(TimeOutTask timeOutTask, long timeout) {
-
this.timeoutTask = timeOutTask;
-
this.timeout = timeout;
-
}
-
-
/**
-
* true if the thread has not ended.
-
*/
-
boolean isRunning = true;
-
-
/**
-
* true if all tasks where done.
-
*/
-
private boolean everythingDone = false;
-
-
/**
-
* if every thing could not be done, an {@link Exception} may have Happens.
-
*/
-
Exception endedWithException = null;
-
-
@Override
-
public void run() {
-
timer.schedule(new TimeOutTimer(Thread.currentThread()), timeout);
-
isRunning = true;
-
try {
-
timeoutTask.run();
-
setEverythingDone(true);
-
} catch (Exception e) {
-
endedWithException = e;
-
}
-
}
-
-
public void setEverythingDone(boolean everythingDone) {
-
this.everythingDone = everythingDone;
-
}
-
-
public boolean isEverythingDone() {
-
return everythingDone;
-
}
-
-
public static interface TimeOutTask {
-
void run() throws Exception;
-
}
-
}
-
-
/**
-
* Classe permettant de mettre fin au thread principal si le temps d'execution maximum est dépassé
-
*/
-
class TimeOutTimer extends TimerTask {
-
Thread t;
-
-
TimeOutTimer(Thread t) {
-
this.t = t;
-
}
-
-
@Override
-
public void run() {
-
if (t != null && t.isAlive()) {
-
t.interrupt();
-
}
-
}
-
}
Et vous pouvez l’utiliser de la sorte :
-
public static void main(String args[]) {
-
long start = System.currentTimeMillis();
-
TimeOutThread myRunnable = new TimeOutThread(new TimeOutTask() {
-
public void run() {
-
try {
-
for (int i = 0; i < 100; i++) {
-
System.out.println("doing something … " + i);
-
// simulate a slow stream.
-
-
synchronized (this) {
-
wait(10);
-
}
-
if (i == 3) {
-
throw new RuntimeException("I am an exception");
-
}
-
}
-
} catch (InterruptedException ie) {
-
System.out.println("MyRunnable error…");
-
ie.printStackTrace();
-
}
-
}
-
}, 1000);
-
myRunnable.start();
-
try {
-
myRunnable.join();
-
long stop = System.currentTimeMillis();
-
-
if (myRunnable.isEverythingDone())
-
System.out.println("all done in " + (stop – start) + " ms.");
-
else {
-
if (myRunnable.endedWithException != null) {
-
System.out.println("End with exception in " + (stop – start) + " ms.");
-
myRunnable.endedWithException.printStackTrace();
-
} else {
-
System.out.println("could not do everything in " + (stop – start) + " ms.");
-
}
-
}
-
} catch (InterruptedException e) {
-
System.out.println("You've killed me!");
-
}
-
System.out.println("fin");
-
}