Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can nested threads throw exceptions for parent thread?

I have a Controller class and a Monitor worker thread. The controller thread looks something like this

public class ControllerA {
    public void ControllerA(){
        try{
            doWork();
        }
        catch(OhNoException e){
        //catch exception
        }

    public void doWork() throws OhNoException{

      new Thread(new Runnable(){
        public void run(){
        //Needs to monitor resources of ControllerA, 
        //if things go wrong, it needs to throw OhNoException for its parent
        }
        }).start();

      //do work here

    }
}

Is such setup feasible? How do I throw exception to the outside of the thread?

like image 915
Bonk Avatar asked Oct 15 '12 13:10

Bonk


2 Answers

How do I throw exception to the outside of the thread?

Couple ways you can do this. You can set a UncaughtExceptionHandler on the thread or you can use an ExecutorService.submit(Callable) and use the exception that you get from the Future.get().

The easiest way is to use the ExecutorService:

ExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();
Future<Void> future = threadPool.submit(new Callable<Void>() {
      public Void call() throws Exception {
         // can throw OhNoException here
         return null;
     }
});
// you need to shut down the pool after submitting the last task
threadPool.shutdown();
try {
   // this waits for your background task to finish, it throws if the task threw
   future.get();
} catch (ExecutionException e) {
    // this is the exception thrown by the call() which could be a OhNoException
    Throwable cause = e.getCause();
     if (cause instanceof OhNoException) {
        throw (OhNoException)cause;
     } else if (cause instanceof RuntimeException) {
        throw (RuntimeException)cause;
     }
}

If you want to use the UncaughtExceptionHandler then you can do something like:

 Thread thread = new Thread(...);
 final AtomicReference throwableReference = new AtomicReference<Throwable>();
 thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
     public void uncaughtException(Thread t, Throwable e) {
         throwableReference.set(e);
     }
 });
 thread.start();
 thread.join();
 Throwable throwable = throwableReference.get();
 if (throwable != null) {
     if (throwable instanceof OhNoException) {
        throw (OhNoException)throwable;
     } else if (throwable instanceof RuntimeException) {
        throw (RuntimeException)throwable;
     }
 }
like image 129
Gray Avatar answered Sep 18 '22 23:09

Gray


Runnable interface cannot throw checked exceptions or return values. In The Callable interface you can call any worker method that return values or throws exceptions. The main tasks of the monitor would be

  1. To declare and initialize the future with the callable instance.

  2. A getResult() method that can have a return future.get(); statement and should declare any checked exceptions in its throws clause for it to be handled by the calling code. In this way we dont have to return a null.

like image 35
clinton Avatar answered Sep 20 '22 23:09

clinton