Domanda

Dire che ho il seguente codice:

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

Ora, se myRunnable lancia un RuntimeExcpetion, come posso prenderlo? Un modo potrebbe essere quello di fornire la mia implementazione ThreadFactory per newSingleThreadExecutor() e impostare uncaughtExceptionHandlers personalizzati per le Threads che vengono fuori di esso. Un altro modo sarebbe quello di avvolgere myRunnable ad un Runnable locale (anonimo) che contiene un -block try-catch. Forse ci sono altre soluzioni simili anche. Ma ... in qualche modo questo si sente sporca, ritengo che non dovrebbe essere questo complicato. C'è una soluzione pulita?

È stato utile?

Soluzione

La soluzione pulita è quella di utilizzare ExecutorService.submit() invece di execute(). In questo modo si restituisce un Future che è possibile utilizzare per recuperare il risultato o eccezione del compito:

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();
}

Altri suggerimenti

Decorare la eseguibile in un altro eseguibile che cattura le eccezioni di runtime e li gestisce:

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));

Perché non chiamare ExecutorService#submit() , ottenere il Future indietro e quindi gestire possibili eccezioni se stessi quando si chiama Future#get() ?

skaffman è corretta in quanto utilizzando submit è l'approccio più pulito. Un approccio alternativo è quello di creare una sottoclasse ThreadPoolExecutor e sovrascrivere afterExecute(Runnable, Throwable). Se si segue questo approccio assicurarsi di chiamare execute(Runnable) , piuttosto che non saranno invocate submit(Runnable) o afterExecute.

Per la descrizione API:

  

Metodo invocato al termine del   esecuzione della proposta praticabile. Questo   metodo viene richiamato dal filo che   eseguito il compito. Se non nullo, la   Throwable è il non rilevata    RuntimeException o Error che causato   esecuzione di interrompere bruscamente.

     

Nota: Quando le azioni sono racchiuse in   attività (come ad esempio FutureTask) sia   esplicitamente o attraverso metodi come   sostengono, questi oggetti dell'attività di cattura e   mantenere eccezioni computazionali, e   in modo da non causare brusca   terminazione, e l'interno   eccezioni sono non passati a questa   Metodo .

un compito (Callable o Runnable) sottoposti a ThreadPoolExecutors sarà convertire in FuturnTask, contiene un puntello di nome callable è uguale al compito si presenta. FuturnTask ha il proprio metodo di run come segue. Tutti eccezione o Throwable throwed in c.call() saranno pescati e messi in un puntello di nome outcome. Quando si chiama il metodo di get FuturnTask, outcome verrà gettato

Da FuturnTask.run Jdk1.8 Codice Sorgente

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);
            }
        }
        ...
    }

se si vuole intercettare l'eccezione:

        
      risposta 1. di skaffman
        
      2. sovrascrittura `afterExecute` quando si nuovo un 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
            }
        }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top