Qual é a melhor abordagem para lidar com exceções lançadas em um thread separado?

Eu estou trabalhando em um projeto J2ME que gera threads de trabalho para inúmeras tarefas, como o download de conteúdo HTTP. O layout básico do thread é semelhante à maioria dos aplicativos java – há um thread principal da interface do usuário e threads de trabalho gerados para fazer coisas nos bastidores. Minha pergunta é qual é a melhor maneira de lidar com exceções que ocorrem nos threads de trabalho?

Eu costumo aderir ao raciocínio de design que a maioria das exceções deve ser percolada, tanto quanto possível. Quando eu escrevo aplicativos de thread único, é comum para mim filtrar as exceções até a camada de interface do usuário e, em seguida, relatá-las em um diálogo de erro para o usuário. Existe uma prática semelhante para aplicativos multithread? O mais intuitivo para mim é capturar exceções no Thread.run () e, em seguida, chamar um invokeLater no thread da interface do usuário para relatá-lo em um diálogo. O problema que vejo aqui é que fora do thread de trabalho morrendo prematuramente, essa abordagem realmente não notifica o segmento de interface do usuário que houve um erro. Eu não vejo uma maneira clara de lançar uma exceção entre os tópicos, por assim dizer.

Obrigado Andy

Você NÃO deve obstruir o código da interface do usuário em seus trabalhadores!

/** * TWO CHOICES: * - Monitor your threads and report errors, * - setup a callback to do something. */ public class ThreadExceptions { /** Demo of {@link RunnableCatch} */ public static void main(String[] argv) throws InterruptedException { final Runnable bad = new NaughtyThread(); // safe1 doesnt have a callback final RunnableCatch safe1 = new RunnableCatch(bad); // safe2 DOES have a callback final RunnableCatch safe2 = new RunnableCatch(bad, new RunnableCallback() { public void handleException(Runnable runnable, Exception exception) { System.out.println("Callback handled: " + exception.getMessage()); exception.printStackTrace(); } }); final Thread t1 = new Thread(safe1, "myThread"); final Thread t2 = new Thread(safe2, "myThread"); t1.start(); t2.start(); t1.join(); t2.join(); if (safe1.getException() != null) { System.out.println("thread finished with exceptions"); safe1.getException().printStackTrace(); } System.out.println("done"); } } /** Throws an exception 50% of the time */ class NaughtyThread implements Runnable { public void run() { try { if (Math.random() > .5) { throw new RuntimeException("badness"); } } finally { System.out.println("ran"); } } } /** Called when an exception occurs */ interface RunnableCallback { void handleException(Runnable runnable, Exception exception); } /** * Catches exceptions thrown by a Runnable, * so you can check/view them later and/or * deal with them from some callback. */ class RunnableCatch implements Runnable { /** Proxy we will run */ private final Runnable _proxy; /** Callback, if any */ private final RunnableCallback _callback; /** @guarded-by(this) */ private Exception _exception; public RunnableCatch(final Runnable proxy) { this(proxy, null); } public RunnableCatch(final Runnable proxy, RunnableCallback target) { _proxy = proxy; _callback = target; } public void run() { try { _proxy.run(); } catch (Exception e) { synchronized (this) { _exception = e; } if (_callback != null) { _callback.handleException(_proxy, e); } } } /** @return any exception that occured, or NULL */ public synchronized Exception getException() { return _exception; } } 

Outra opção diferente do que o Stuph forneceu é definir exceções no segmento local. Se outra exceção ocorrer antes que a exceção seja limpa, ocorrerá uma declaração. Isso pelo menos dá a alguém a chance de notar a exceção e processá-la.