Mon extrait de code:
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
Task t = new Task(response,inputToPass,pTypes,unit.getInstance(),methodName,unit.getUnitKey());
Future<SCCallOutResponse> fut = executor.submit(t);
response = fut.get(unit.getTimeOut(),TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
// if the task is still running, a TimeOutException will occur while fut.get()
cat.error("Unit " + unit.getUnitKey() + " Timed Out");
response.setVote(SCCallOutConsts.TIMEOUT);
} catch (InterruptedException e) {
cat.error(e);
} catch (ExecutionException e) {
cat.error(e);
} finally {
executor.shutdown();
}
Comment dois-je gérer les InterruptedException
et ExecutionException
dans le code?
Et dans quels cas, ces exceptions sont-elles levées?
ExecutionException
et InterruptedException
sont deux choses très différentes.
ExecutionException
enveloppe quelle que soit l'exception que le fil en cours d'exécution a jeté, donc si votre fil était, par exemple, en train de faire une sorte de IO qui a provoqué le lancement d'une IOException
, celui-ci serait enveloppé dans un ExecutionException
et renversé.
Un InterruptedException
n'est pas le signe que quelque chose a mal tourné. Il est là pour vous permettre de faire savoir à vos discussions à quel moment il est temps de s’arrêter afin qu’elles puissent terminer leur travail en cours et se quitter en douceur. Dites que je veux que mon application cesse de fonctionner, mais je ne veux pas que mes threads abandonnent ce qu'ils font au milieu de quelque chose (ce qui se produirait si je leur créais des threads démon). Donc, lorsque l'application est en train d'être arrêtée, mon code appelle la méthode d'interruption sur ces threads, ce qui définit l'indicateur d'interruption sur eux et la prochaine fois que ces threads attendent ou se mettent en sommeil, ils vérifient l'indicateur d'interruption et lancent une InterruptedException
, que je peux utiliser. pour sortir de toute logique de traitement/boucle en boucle infinie dans laquelle les threads sont engagés. (Et si le thread n'attend pas ou ne dort pas, il peut simplement vérifier l'indicateur d'interruption périodiquement.) Il s'agit donc d'une instance d'une exception utilisée. pour changer le flux logique. La seule raison pour laquelle vous le consignerez est dans un exemple de programme pour vous montrer ce qui se passe ou si vous corrigez un problème où la logique d'interruption ne fonctionne pas correctement.
InterruptedException
sera levé si interrupt
est appelé sur le thread en attente avant la fin du calcul.
ExecutionException
sera levé si le calcul impliqué (Task
dans ce cas) lève une exception elle-même.
La façon dont vous souhaitez gérer cela dépendra entièrement de votre application.
EDIT: Voici une démonstration de l'interruption:
import Java.util.concurrent.*;
public class Test
{
public static void main(String[] args) throws Exception
{
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> future = executor.submit(new SlowCallable());
executor.submit(new Interruptor(Thread.currentThread()));
try
{
System.out.println(future.get());
}
catch (InterruptedException e)
{
System.out.println("I was interrupted");
}
}
private static class Interruptor implements Callable<String>
{
private final Thread threadToInterrupt;
Interruptor(Thread threadToInterrupt)
{
this.threadToInterrupt = threadToInterrupt;
}
public String call() throws Exception
{
Thread.sleep(2000);
threadToInterrupt.interrupt();
return "interrupted other thread";
}
}
private static class SlowCallable implements Callable<String>
{
public String call() throws Exception
{
Thread.sleep(5000);
return "finished";
}
}
}
L'article d'IBM Developer Works Gestion de l'InterruptedException contient des conseils sur la façon de gérer InterruptedException
.
Exemple de code pour renvoyer trois types d'exceptions.
import Java.util.concurrent.*;
import Java.util.*;
public class ExceptionDemo{
public static void main(String args[]){
int poolSize=1;
int maxPoolSize=1;
int queueSize=30;
long aliveTive=60;
ArrayBlockingQueue<Runnable> queue= new ArrayBlockingQueue<Runnable>(queueSize);
ThreadPoolExecutor executor= new ThreadPoolExecutor(poolSize,maxPoolSize,aliveTive,
TimeUnit.MILLISECONDS,queue);
List<Future> futures = new ArrayList<Future>();
for ( int i=0; i < 5; i++){
futures.add(executor.submit(new RunnableEx()));
}
for ( Iterator it = futures.iterator(); it.hasNext();){
try {
Future f = (Future)it.next();
f.get(4000,TimeUnit.MILLISECONDS);
}catch(TimeoutException terr){
System.out.println("Timeout exception");
terr.printStackTrace();
}
catch(InterruptedException ierr){
System.out.println("Interrupted exception:");
ierr.printStackTrace();
}catch(ExecutionException err){
System.out.println("Exeuction exception:");
err.printStackTrace();
Thread.currentThread().interrupt();
}
}
executor.shutdown();
}
}
class RunnableEx implements Runnable{
public void run() {
// code in here
System.out.println("Thread name:"+Thread.currentThread().getName());
try{
Random r = new Random();
if (r.nextInt(2) == 1){
Thread.sleep(2000);
}else{
Thread.sleep(4000);
}
System.out.println("eee:"+1/0);
}catch(InterruptedException irr){
irr.printStackTrace();
}
}
}
sortie:
Thread name:pool-1-thread-1
Timeout exception
Thread name:pool-1-thread-1
Java.util.concurrent.TimeoutException
at Java.util.concurrent.FutureTask.get(FutureTask.Java:201)
at ExceptionDemo.main(ExceptionDemo.Java:20)
Thread name:pool-1-thread-1
Exeuction exception:
Java.util.concurrent.ExecutionException: Java.lang.ArithmeticException: / by zero
at Java.util.concurrent.FutureTask.report(FutureTask.Java:122)
at Java.util.concurrent.FutureTask.get(FutureTask.Java:202)
at ExceptionDemo.main(ExceptionDemo.Java:20)
Caused by: Java.lang.ArithmeticException: / by zero
at RunnableEx.run(ExceptionDemo.Java:49)
at Java.util.concurrent.Executors$RunnableAdapter.call(Executors.Java:471)
at Java.util.concurrent.FutureTask.run(FutureTask.Java:262)
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1145)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:615)
at Java.lang.Thread.run(Thread.Java:744)
Interrupted exception:
Java.lang.InterruptedException
at Java.util.concurrent.FutureTask.awaitDone(FutureTask.Java:400)
at Java.util.concurrent.FutureTask.get(FutureTask.Java:199)
at ExceptionDemo.main(ExceptionDemo.Java:20)
Timeout exception
Java.util.concurrent.TimeoutException
at Java.util.concurrent.FutureTask.get(FutureTask.Java:201)
Thread name:pool-1-thread-1
at ExceptionDemo.main(ExceptionDemo.Java:20)
Thread name:pool-1-thread-1
Timeout exception
Java.util.concurrent.TimeoutException
at Java.util.concurrent.FutureTask.get(FutureTask.Java:201)
at ExceptionDemo.main(ExceptionDemo.Java:20)
TimeoutException : Exception levée lorsqu'une opération de blocage expire.
Dans l'exemple ci-dessus, certaines tâches prennent plus de temps (en raison d'une veille de 4 secondes) et bloquent le fonctionnement de get()
sur Future
Augmentez le délai d'expiration ou optimisez la tâche Runnable.
ExecutionException : Exception levée lors d'une tentative d'extraction du résultat d'une tâche qui a été annulée en lançant une exception => Le calcul a renvoyé une exception
Dans l'exemple ci-dessus, cette Exception
est simulée par ArithmeticException: / by zero
En règle générale, vous devriez corriger la cause du problème si elle est triviale, comme indiqué dans l'exemple.
InterruptedException : Émis lorsqu'un thread est en attente, en veille ou occupé d'une autre manière et que le thread est interrompu, que ce soit avant ou pendant l'activité.
Dans l'exemple ci-dessus, cette Exception
est simulée en interrompant le thread actuel pendant ExecutionException
.
Généralement, vous devriez attraper cela et ne pas agir dessus.