2010-10-06 30 views
38

Ho un programma ScheduledThreadPoolExecutor che sembra mangiare eccezioni. Voglio che il mio servizio esecutore mi informi se un Runnable inviato genera un'eccezione.Gestione delle eccezioni in ThreadPools

Per esempio, mi piacerebbe il codice sottostante per lo meno di stampa del IndexArrayOutOfBoundsException stackTrace

threadPool.scheduleAtFixedRate(
    new Runnable() { 
    public void run() { 
     int[] array = new array[0]; 
     array[42] = 5; 
    } 
    }, 
    1000, 
    1500L, 
    TimeUnit.MILLISECONDS); 

Come una domanda lato. C'è un modo per scrivere un blocco catch try generale per ScheduledThreadPoolExecutor?

////////// FINE domanda iniziale //////////////

Come suggerito il seguente Decorator funziona bene.

public class CatcherTask implements Runnable{ 

    Runnable runMe; 

    public CatcherTask(Runnable runMe) { 
     this.runMe = runMe; 
    } 

    public void run() { 
     try { 
      runMe.run(); 
     } catch (Exception ex){ 
      ex.printStackTrace(); 
     } 
    } 
} 
+3

Ottima domanda. Mi chiedo perché solo poche persone si imbattono in questo. – whiskeysierra

+0

Vedere anche http://stackoverflow.com/questions/1687977/how-to-properly-catch-runtimeexceptions-from-executors – Raedwald

risposta

22

Ho scritto un piccolo post su questo problema qualche tempo fa. Sono disponibili due opzioni:

  1. utilizzare il solution fornito da Colin Herbert o
  2. utilizzare una versione modificata di Mark Peters solution ma invece di assegnare un UncaughtExceptionHandler si avvolge presentato ciascuno eseguibile in un eseguibile della propria che esegue (chiama run) il vero eseguibile all'interno di un blocco try-catch.

EDIT
Come sottolineato da Mark, è importante per avvolgere il Runnable passati a ScheduledExecutorService invece di quello passato al ThreadFactory.

+0

Va bene, l'ho confermato e ho cancellato la mia risposta. Grazie! Sentiti libero di modificare il tuo passaggio 2 per entrare nei dettagli. –

+2

In realtà ho provato il n. 2 e non sono riuscito a farlo funzionare. L'eccezione è stata rilevata ben al di sopra del mio blocco try/catch nel delegato Runnable, quindi questo sembra soccombere allo stesso problema di UncaughtExceptionHandler. –

+0

Ho appena accettato questo, ma Mark sta dicendo che Decorare le attività inviate con un try/catch non lo è ... Ci proverò. – Ivan

12

Warning: Questo metodo non è applicabile a linea esecutori pool di thread. Questa risposta non è stata eliminata per la sua rilevanza con altri esecutori di pool di thread. Vedi Willi's answer.

Override il ThreadFactory che invia un Discussioni UncaughtExceptionHandler:

ThreadPoolExecutor exec = new ThreadPoolExecutor...; 

exec.setThreadFactory(new ExceptionCatchingThreadFactory(exec.getThreadFactory())); 
//go on to submit tasks... 


private static class ExceptionCatchingThreadFactory implements ThreadFactory { 
    private final ThreadFactory delegate; 

    private ExceptionCatchingThreadFactory(ThreadFactory delegate) { 
     this.delegate = delegate; 
    } 

    public Thread newThread(final Runnable r) { 
     Thread t = delegate.newThread(r); 
     t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { 
      @Override 
      public void uncaughtException(Thread t, Throwable e) { 
       e.printStackTrace(); //replace with your handling logic. 
      } 
     }); 
     return t; 
    } 
} 
+4

'UncaughExceptionHandler' non funziona con i runnables pianificati. – whiskeysierra

+0

@Willi: fammi verificare e poi lo cancellerò se confermo. –

+1

Annullamento dell'eliminazione poiché sembra ancora utile per gli esecutori di pool di thread non pianificati. –

0

considerare l'aggiunta di un evento statico nella vostra ScheduledThreadPoolExecutor classe che le tue mansioni può chiamare se viene generata un'eccezione. In questo modo, puoi sfruttare quell'evento per acquisire e gestire le eccezioni che si verificano all'interno dei tuoi thread.

+1

'ScheduledThreadPoolExecutor' è in' java.util.concurrent' ... – whiskeysierra

5

È possibile utilizzare il metodo get() dal numero Future che si ottiene chiamando scheduleAtFixedRate(). Lancia un ExecutionException se si verifica un errore durante l'esecuzione del thread.

+0

Come funziona per le chiamate successive? per esempio. come si ottiene un futuro per la seconda invocazione, dopo che il primo è ritornato con successo? –

+0

@Mark Se un'esecuzione fallita, non ci sarà una seconda (o terza, ...) esecuzione. Copiato dal javadoc originale: * Se qualsiasi esecuzione dell'attività riscontra un'eccezione, le esecuzioni successive vengono soppresse. * – whiskeysierra

+0

@Willi: Quindi suppongo di essere confuso sull'affermazione dell'OP "sembra che mangi le eccezioni ..." se è corri solo una volta. –

2

È inoltre possibile utilizzare , che espone un metodo per impostare un gestore errori e fa tutto ciò che si desidera. Il comportamento predefinito dipende dal tipo di attività:

Se lo ErrorHandler fornito non è nullo, verrà utilizzato. In caso contrario, le attività ripetute avranno errori soppressi per impostazione predefinita mentre le attività one-shot avranno errori propagati per impostazione predefinita poiché tali errori potrebbero essere previsti tramite il valore restituito Future. In entrambi i casi, gli errori verranno registrati.

Se si desidera utilizzare solo la parte di avvolgimento e non il TaskScheduler è possibile utilizzare

TaskUtils.decorateTaskWithErrorHandler(task, errorHandler, isRepeatingTask) 

cui il TaskScheduler usa internamente.

2

È possibile creare sottoclasse ScheduledThreadPoolExecutor e sovrascrivere il metodo afterExecute per gestire eccezioni ed errori per qualsiasi tipo di Runnable inviato.