Question

Dites que j'ai le code suivant:

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(myRunnable);

Maintenant, si myRunnable jette un RuntimeExcpetion, comment puis-je attraper? Une façon serait de fournir ma propre mise en œuvre de ThreadFactory à newSingleThreadExecutor() et mettre uncaughtExceptionHandlers personnalisés pour les Threads qui sortent de celui-ci. Une autre façon serait d'envelopper myRunnable à un Runnable local (anonyme) qui contient un -bloc try-catch. Peut-être il y a d'autres solutions de contournement semblables aussi. Mais ... en quelque sorte cela se sent sale, je pense qu'il ne devrait pas être si compliqué. Y at-il une solution propre?

Était-ce utile?

La solution

La solution propre est d'utiliser ExecutorService.submit() au lieu de execute(). Cela vous renvoie une Future que vous pouvez utiliser pour récupérer le résultat ou l'exception de la tâche:

ExecutorService executor = Executors.newSingleThreadExecutor();
Runnable task = new Runnable() {
  public void run() {
    throw new RuntimeException("foo");
  }
};

Future<?> future = executor.submit(task);
try {
  future.get();
} catch (ExecutionException e) {
  Exception rootException = e.getCause();
}

Autres conseils

Décorez le runnable dans un autre runnable qui attrape les exceptions d'exécution et les poignées:

public class REHandler implements Runnable {
    Runnable delegate;
    public REHandler (Runnable delegate) {
        this.delegate = delegate;
    }
    public void run () {
        try {
            delegate.run ();
        } catch (RuntimeException e) {
            ... your fancy error handling here ...
        }
    }
}

executor.execute(new REHandler (myRunnable));

Pourquoi ne pas appeler ExecutorService#submit() , obtenir le Future arrière et gérer vous-même des exceptions possibles lors de l'appel Future#get() ?

skaffman est correct que l'utilisation submit est la plus propre approche. Une autre approche consiste à sous-classe ThreadPoolExecutor et remplacer afterExecute(Runnable, Throwable). Si vous suivez cette approche veillez à appeler execute(Runnable) plutôt que submit(Runnable) ou afterExecute ne seront pas invoquées.

Par la description de l'API:

  

Méthode invoquée lors de l'achèvement de   exécution du Runnable donné. Cette   méthode est appelée par le fil qui   exécuté la tâche. Si non nul, la   Throwable est le uncaught    RuntimeException ou Error qui fait   exécution de mettre fin abruptement.

     

Remarque: lorsque les actions sont enfermés dans   tâches (telles que FutureTask) soit   explicitement ou via des méthodes telles que   soumettre, ces objets de tâche attraper et   maintenir des exceptions de calcul, et   de sorte qu'ils ne causent pas de brusque   la terminaison, et l'intérieur   exceptions sont pas transmis à cette   Procédé .

une tâche (ou Callable Runnable) soumis à ThreadPoolExecutors sera convertir en FuturnTask, contient un accessoire nommé callable est égal à la tâche que vous soumettez. FuturnTask a sa propre méthode de run comme suit. Toutes exception ou throwable throwed dans c.call() seront attrapés et mis en un accessoire nommé outcome. Lorsque vous appelez la méthode get de FuturnTask, outcome sera throwed

De FuturnTask.run Jdk1.8 code source

public void run() {
        ...
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    // save ex into `outcome` prop
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        }
        ...
    }

si vous voulez attraper l'exception:

        
      1. La réponse de skaffman
        
      2. Ecraser `afterExecute` lorsque vous une nouvelle ThreadPoolExecutor
        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
            Throwable cause = null;
            if (t == null && r instanceof Future) {
                try {
                    ((Future<?>) r).get();
                } catch (InterruptedException | ExecutionException e) {
                    cause = e;
                }
            } else if (t != null) {
                cause = t;
            }
            if (cause != null) {
                // log error
            }
        }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top