Pergunta

dizer que tenho o seguinte código:

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

Agora, se myRunnable lança uma RuntimeExcpetion, como posso pegá-lo? Uma forma seria para abastecer minha própria implementação ThreadFactory para newSingleThreadExecutor() e definir uncaughtExceptionHandlers personalizados para os Threads que vêm de fora. Outra forma seria para embrulhar myRunnable a um (anônimo) Runnable local que contém um -bloco try-catch. Talvez existam outras soluções semelhantes também. Mas ... de alguma forma este se sente sujo, eu sinto que ele não deve ser tão complicado. Existe uma solução limpa?

Foi útil?

Solução

A solução limpa é usar ExecutorService.submit() vez de execute(). Isso você um Future que você pode usar para recuperar o resultado ou exceção da tarefa retornos:

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

Outras dicas

Decore o executável em outro executável que captura as exceções de tempo de execução e manipula-los:

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 que não chamar ExecutorService#submit() , obter o Future para trás e, em seguida, lidar com possíveis exceções si mesmo ao chamar Future#get() ?

skaffman é correto que usando submit é a abordagem mais limpa. Uma abordagem alternativa é a subclasse ThreadPoolExecutor e afterExecute(Runnable, Throwable) override. Se você seguir esta abordagem certifique-se de chamada execute(Runnable) em vez de submit(Runnable) ou afterExecute não será invocado.

Pela descrição API:

Método invocado após a conclusão da execução do dado Runnable. Esta método é invocado pelo segmento que executado a tarefa. Se não-nulo, o Throwable é o uncaught RuntimeException ou Error que causou execução para terminar abruptamente.

Nota: Quando as ações são colocados tarefas (tais como FutureTask) tanto explicitamente ou através de métodos tais como apresentar, essas tarefas objetos capturar e manter exceções computacionais, e para que eles não causam abrupta de terminação, e o interno as exceções são não passado para este método .

uma tarefa (Callable ou Runnable) submetidos a ThreadPoolExecutors será convertido a um FuturnTask, contém um suporte chamado callable é igual a tarefa de enviar. FuturnTask tem seu próprio método run como segue. Todos exceção ou throwable Throwed em c.call() será catched e colocar em um suporte chamado outcome. Ao chamar método get de FuturnTask, outcome será Throwed

FuturnTask.run partir do código fonte Jdk1.8

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 você deseja capturar a exceção:

      1. de skaffman resposta
        2. sobrescrever `afterExecute` quando você novo a 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top