193 votes

Comment attraper une exception à partir d'un thread

J'ai une classe principale Java, dans la classe, je démarre un nouveau fil, dans la classe principale, il attend que le fil meurt. À un moment donné, je lance une exception d'exécution à partir du thread, mais je ne peux pas attraper l'exception lancée par le thread dans la classe principale.

Voici le code :

public class Test extends Thread
{
  public static void main(String[] args) throws InterruptedException
  {
    Test t = new Test();

    try
    {
      t.start();
      t.join();
    }
    catch(RuntimeException e)
    {
      System.out.println("** RuntimeException from main");
    }

    System.out.println("Main stoped");
  }

  @Override
  public void run()
  {
    try
    {
      while(true)
      {
        System.out.println("** Started");

        sleep(2000);

        throw new RuntimeException("exception from thread");
      }
    }
    catch (RuntimeException e)
    {
      System.out.println("** RuntimeException from thread");

      throw e;
    } 
    catch (InterruptedException e)
    {

    }
  }
}

Quelqu'un sait pourquoi ?

250voto

Dan Cruz Points 7016

Utilisez un Thread.UncaughtExceptionHandler .

Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread th, Throwable ex) {
        System.out.println("Uncaught exception: " + ex);
    }
};
Thread t = new Thread() {
    @Override
    public void run() {
        System.out.println("Sleeping ...");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println("Interrupted.");
        }
        System.out.println("Throwing exception ...");
        throw new RuntimeException();
    }
};
t.setUncaughtExceptionHandler(h);
t.start();

18 votes

Que puis-je faire si je veux transmettre l'exception à un niveau supérieur ?

6 votes

@rodi enregistre ex dans une variable volatile que le niveau supérieur peut voir dans le handler (par exemple, une variable membre). A l'extérieur, vérifier si null, sinon lancer. Ou étendre UEH avec un nouveau champ volatile et y stocker l'exception.

1 votes

Je veux attraper une exception à l'intérieur de mon thread - sans qu'il soit arrêté. Est-ce que cela pourrait être utile ?

52voto

abyx Points 15304

C'est parce que les exceptions sont locales à un thread, et que votre thread principal ne voit pas l'objet de l'exception. run méthode. Je vous suggère de lire davantage sur le fonctionnement du threading, mais pour résumer rapidement : votre appel à la méthode start démarre un autre fil, sans aucun rapport avec le fil principal. L'appel à join attend simplement que cela soit fait. Une exception lancée dans un thread et qui n'est jamais attrapée met fin à celui-ci, c'est pourquoi join revient sur votre fil principal, mais l'exception elle-même est perdue.

Si vous voulez être au courant de ces exceptions non saisies, vous pouvez essayer ceci :

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("Caught " + e);
    }
});

Vous trouverez plus d'informations sur le traitement des exceptions non capturées dans le document suivant ici .

1 votes

J'aime ça ! Définir le gestionnaire avec la méthode statique Thread.setDefaultUncaughtExceptionHandler() attrape également les exceptions dans le fil "main".

39voto

Talha Ahmed Khan Points 5060

Cela explique la transition d'état des threads en fonction de l'apparition ou non d'une exception :

Threads and Exception Handling

Source : http://www-public.imtbs-tsp.eu/~gibson/Teaching/CSC7322/L8-ExceptionsAndThreads.pdf

13 votes

Avez-vous créé le diagramme ? Si non, quelle est la source ?

30voto

Peter Lawrey Points 229686

Très probablement ;

  • vous n'avez pas besoin de transmettre l'exception d'un thread à l'autre.
  • si vous voulez gérer une exception, faites-le dans le thread qui l'a déclenchée.
  • votre thread principal n'a pas besoin d'attendre le thread d'arrière-plan dans cet exemple, ce qui signifie en fait que vous n'avez pas besoin du tout d'un thread d'arrière-plan.

Cependant, supposons que vous ayez besoin de gérer une exception provenant d'un autre thread enfant. J'utiliserais un ExecutorService comme ceci :

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Void> future = executor.submit(new Callable<Void>() {
    @Override
    public Void call() throws Exception {
        System.out.println("** Started");
        Thread.sleep(2000);
        throw new IllegalStateException("exception from thread");
    }
});
try {
    future.get(); // raises ExecutionException for any uncaught exception in child
} catch (ExecutionException e) {
    System.out.println("** RuntimeException from thread ");
    e.getCause().printStackTrace(System.out);
}
executor.shutdown();
System.out.println("** Main stopped");

imprime

** Started
** RuntimeException from thread 
java.lang.IllegalStateException: exception from thread
    at Main$1.call(Main.java:11)
    at Main$1.call(Main.java:6)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
** Main stopped

2 votes

Mais ne future.get() attendre ou bloquer jusqu'à ce que le thread ait terminé son exécution ?

0 votes

@GregorValentin il attend/bloque jusqu'à ce que le thread ait terminé le Runnable/Callable.

9voto

denis.solonenko Points 6348

Veuillez jeter un coup d'œil à Thread.UncaughtExceptionHandler

Une meilleure solution (alternative) consiste à utiliser Appelable y Futur pour obtenir le même résultat...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X