Pregunta

Decir que tengo el siguiente código:

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

Ahora, si myRunnable lanza un RuntimeExcpetion, cómo puedo alcanzarlo?Una forma sería la de proporcionar mi propio ThreadFactory aplicación a newSingleThreadExecutor() y configurar de forma personalizada uncaughtExceptionHandlers para la Threads que salen de ella.De otra manera sería envolver myRunnable a un local (anónimo) Runnable que contiene un try-catch -bloque.Tal vez hay otras soluciones similares también.Pero...de alguna manera esto se siente sucio, siento que no debería ser tan complicado.Hay una solución limpia?

¿Fue útil?

Solución

La solución limpia es utilizar ExecutorService.submit() en lugar de execute(). Esto le devuelve una Future que se puede utilizar para recuperar el resultado o excepción de la tarea:

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

Otros consejos

Decorar el ejecutable en otro ejecutable que atrapa las excepciones de tiempo de ejecución y los maneja:

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

¿Por qué no llamar ExecutorService#submit() , obtener la Future atrás y luego manejar las posibles excepciones a sí mismo al llamar Future#get() ?

skaffman es correcto en que el uso de submit es el enfoque más limpio. Un enfoque alternativo es una subclase ThreadPoolExecutor y anular afterExecute(Runnable, Throwable). Si sigue este enfoque asegúrese de llamar execute(Runnable) en lugar de no ser invocados submit(Runnable) o afterExecute.

Por la descripción de la API:

  

método invocado una vez finalizado   ejecución de lo dado Ejecutable. Esta   método es invocado por el hilo que   ejecutado la tarea. Si no es nulo, el   Throwable es la no detectada    RuntimeException o Error la causada   la ejecución de terminar abruptamente.

     

Nota: Cuando las acciones están encerrados en   tareas (tales como FutureTask) o bien   explícitamente o por medio de métodos tales como   presentar, estos objetos de la tarea y atrapan   mantener excepciones computacionales, y   de modo que no causen abrupta   terminación, y la interna   excepciones son no pasaron a esta   método .

una tarea(Callable o Runnable enviadas a ThreadPoolExecutors será convertir a un FuturnTask, contiene una proposición con nombre callable es igual a la tarea de enviar.FuturnTask tiene su propio run método de la siguiente manera.Toda excepción o arrojar tirado en c.call() será apresado y puesto en un accesorio llamado outcome.Cuando se llama a FuturnTask del get método, outcome será lanzado

FuturnTask.ejecutar Desde Jdk1.8 Código Fuente

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 desea capturar la excepción :

      1.skaffman la respuesta
      2.sobreescribir `afterExecute` cuando un nuevo 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
            }
        }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top