CMZS
CMZS

Reputation: 601

handle java exception in Thread.run

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

Upvotes: 1

Views: 7100

Answers (3)

AnatolyG
AnatolyG

Reputation: 1587

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.

Upvotes: 1

Andy Turner
Andy Turner

Reputation: 140328

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

Upvotes: 4

PeterS
PeterS

Reputation: 2954

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

Upvotes: 0

Related Questions