1

I have an inner class that extends Thread

private class TestStart extends Thread {
    public void run() {
        try {
            startServer();
        }
        catch (Exception e) {
            /// How to handle it?
        }
    }
} 

The caller in the main thread:

public void start() throws Exception {
    Thread st = new TestStart();
    st.start();
}

Method startServer() throws Exception by its API, so I have to use try-catch as Thread.run() does not "throws" exception in method definition. I need to bubble up the caught exception into the main thread to handle it. Is there an easy way to do it? Thanks

CMZS
  • 601
  • 6
  • 21
  • 1
    How do you start these threads? If you were using an `ExecutorService`, you'd be able to submit a `Runnable` and get a `Future>`; calling `get()` on that `Future` would yield an `ExecutionException` if an exception were thrown in the `Runnable`. – Andy Turner May 04 '16 at 20:23
  • See [http://stackoverflow.com/questions/1369204/how-to-throw-a-checked-exception-from-a-java-thread](http://stackoverflow.com/questions/1369204/how-to-throw-a-checked-exception-from-a-java-thread) – Ron C May 04 '16 at 20:26

3 Answers3

4

If you use an ExecutorService instead of using raw threads, you can be notified of uncaught exceptions:

class MyCallable implements Callable<Void> {
  @Override public Void call() throws Exception {
    // Do something - you don't need to catch Exception as Callable throws it.
    // ...

    return null;  // A return is necessary from a Callable.
  }
}

Create an executor service somewhere, e.g.:

ExecutorService executor = Executors.newFixedThreadPool(1);

Then, in the code where you start the thread:

Future<?> future = executor.submit(new MyCallable());

try {
  future.get();  // Blocks until the Callable completes.
} catch (ExecutionException e) {
  // You reach here if an exception is thrown in the Callable -
  // The exception is accessible via e.getCause().
}
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
1

There is a few possible solutions. For example:

  1. Use setUncaughtExceptionHandler()/setDefaultUncaughtExceptionHandler() and change your try/catch

    try {
        startServer();
    }
    catch (RuntimeException e) {
        throw e;
    }
    catch (Exception e) {
        throw new RuntimeException(e);
    }
    
  2. Or use your custom listener

    private class TestStart extends Thread {
        private final ServerStateListener lnr;
    
        TestStart(ServerStateListener lnr) {
            this.lnr = lnr;
        }
    
        public void run() {
            try {
                startServer();
                lnr.onServerStarted();
            }
            catch (Exception e) {
                lnr.onServerStoppedByError(e);
            }
        }
    }
    
  3. Or just save Exception and read it after .join

    private class TestStart extends Thread {
        private Exception error; // if you start and join and read this property within one thread, you don't need to use volatile, otherwise do it for safe publication
    
        public void run() {
            try {
                startServer();
            }
            catch (Exception e) {
                error = e;
            }
        }
    
        public Exception getError() {
            return error;
        }
    } 
    
  4. Or use ExecutorService/Callable instead of your own thread as Andy suggested.

AnatolyG
  • 1,557
  • 8
  • 14
0

Set a new exception handler on your Thread.

   st.setDefaultUncaughtExceptionHandler(new Thread.
             UncaughtExceptionHandler() {
               public void uncaughtException(Thread t, Throwable e) {
               System.out.println(t + " throws exception: " + e);
             }
   });

And place that code before your start();

PeterS
  • 2,818
  • 23
  • 36