How to catch an Exception from a thread

JavaMultithreading

Java Problem Overview


I have Java main class, in the class, I start a new thread, in the main, it waits until the thread dies. At some moment, I throw a runtime exception from the thread, but I can't catch the exception thrown from the thread in the main class.

Here is the code:

public class Test extends Thread
{
  public static void main(String[] args) throws InterruptedException
  {
    Test t = new Test();
    
    try
    {
      t.start();
      t.join();
    }
    catch(RuntimeException e)
    {
      System.out.println("** RuntimeException from main");
    }
    
    System.out.println("Main stoped");
  }
  
  @Override
  public void run()
  {
    try
    {
      while(true)
      {
        System.out.println("** Started");
        
        sleep(2000);
        
        throw new RuntimeException("exception from thread");
      }
    }
    catch (RuntimeException e)
    {
      System.out.println("** RuntimeException from thread");
      
      throw e;
    } 
    catch (InterruptedException e)
    {
      
    }
  }
}

Anybody knows why?

Java Solutions


Solution 1 - Java

Use a Thread.UncaughtExceptionHandler.

Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread th, Throwable ex) {
        System.out.println("Uncaught exception: " + ex);
    }
};
Thread t = new Thread() {
    @Override
    public void run() {
        System.out.println("Sleeping ...");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println("Interrupted.");
        }
        System.out.println("Throwing exception ...");
        throw new RuntimeException();
    }
};
t.setUncaughtExceptionHandler(h);
t.start();

Solution 2 - Java

That's because exceptions are local to a thread, and your main thread doesn't actually see the run method. I suggest you read more about how threading works, but to quickly summarize: your call to start starts up a different thread, totally unrelated to your main thread. The call to join simply waits for it to be done. An exception that is thrown in a thread and never caught terminates it, which is why join returns on your main thread, but the exception itself is lost.

If you want to be aware of these uncaught exceptions you can try this:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
	@Override
	public void uncaughtException(Thread t, Throwable e) {
		System.out.println("Caught " + e);
	}
});

More information about uncaught exception handling can be found here.

Solution 3 - Java

This explains the state transition of threads dependening on whether an exceptions occured or not:

Threads and Exception Handling

Source : http://www-public.imtbs-tsp.eu/~gibson/Teaching/CSC7322/L8-ExceptionsAndThreads.pdf

Solution 4 - Java

Most likely;

  • you don't need to pass the exception from one thread to another.
  • if you want to handle an exception, just do it in the thread which threw it.
  • your main thread doesn't need to wait from the background thread in this example, which actually means you don't need a background thread at all.

However, lets assume you do need to handle an exception from a child thread another. I would use an ExecutorService like this:

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Void> future = executor.submit(new Callable<Void>() {
    @Override
    public Void call() throws Exception {
        System.out.println("** Started");
        Thread.sleep(2000);
        throw new IllegalStateException("exception from thread");
    }
});
try {
    future.get(); // raises ExecutionException for any uncaught exception in child
} catch (ExecutionException e) {
    System.out.println("** RuntimeException from thread ");
    e.getCause().printStackTrace(System.out);
}
executor.shutdown();
System.out.println("** Main stopped");

prints

** Started
** RuntimeException from thread 
java.lang.IllegalStateException: exception from thread
	at Main$1.call(Main.java:11)
	at Main$1.call(Main.java:6)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:662)
** Main stopped

Solution 5 - Java

Please take a look at Thread.UncaughtExceptionHandler

Better (alternative) way is to use Callable and Future to get the same result...

Solution 6 - Java

Use Callable instead of Thread, then you can call Future#get() which throws any exception that the Callable threw.

Solution 7 - Java

Currently you are catching only RuntimeException, a sub class of Exception. But your application may throw other sub-classes of Exception. Catch generic Exception in addition to RuntimeException

Since many of things have been changed on Threading front, use advanced java API.

Prefer advance java.util.concurrent API for multi-threading like ExecutorService or ThreadPoolExecutor.

You can customize your ThreadPoolExecutor to handle exceptions.

Example from oracle documentation page:

Override

protected void afterExecute(Runnable r,
                            Throwable t)

> Method invoked upon completion of execution of the given Runnable. This method is invoked by the thread that executed the task. If non-null, the Throwable is the uncaught RuntimeException or Error that caused execution to terminate abruptly.

Example code:

class ExtendedExecutor extends ThreadPoolExecutor {
   // ...
   protected void afterExecute(Runnable r, Throwable t) {
     super.afterExecute(r, t);
     if (t == null && r instanceof Future<?>) {
       try {
         Object result = ((Future<?>) r).get();
       } catch (CancellationException ce) {
           t = ce;
       } catch (ExecutionException ee) {
           t = ee.getCause();
       } catch (InterruptedException ie) {
           Thread.currentThread().interrupt(); // ignore/reset
       }
     }
     if (t != null)
       System.out.println(t);
   }
 }

Usage:

ExtendedExecutor service = new ExtendedExecutor();

I have added one constructor on top of above code as:

 public ExtendedExecutor() { 
	   super(1,5,60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(100));
   }

You can change this constructor to suit your requirement on number of threads.

ExtendedExecutor service = new ExtendedExecutor();
service.submit(<your Callable or Runnable implementation>);

Solution 8 - Java

I faced the same issue ... little work around (only for implementation not anonymous objects ) ... we can declare the class level exception object as null ... then initialize it inside the catch block for run method ... if there was error in run method,this variable wont be null .. we can then have null check for this particular variable and if its not null then there was exception inside the thread execution.

class TestClass implements Runnable{
    private Exception ex;

        @Override
        public void run() {
            try{
                //business code
               }catch(Exception e){
                   ex=e;
               }
          }

      public void checkForException() throws Exception {
            if (ex!= null) {
                throw ex;
            }
        }
}     

call checkForException() after join()

Solution 9 - Java

Also from Java 8 you can write Dan Cruz answer as:

Thread t = new Thread(()->{
            System.out.println("Sleeping ...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("Interrupted.");
            }
            System.out.println("Throwing exception ...");
            throw new RuntimeException(); });
    

t.setUncaughtExceptionHandler((th, ex)-> log(String.format("Exception in thread %d id: %s", th.getId(), ex)));
t.start();

Solution 10 - Java

AtomicReference is also a solution to pass the error to the main thread .Is same approach like the one of Dan Cruz .

AtomicReference<Throwable> errorReference = new AtomicReference<>();

    Thread thread = new Thread() {
        public void run() {
            throw new RuntimeException("TEST EXCEPTION");

        }
    };
    thread.setUncaughtExceptionHandler((th, ex) -> {
        errorReference.set(ex);
    });
    thread.start();
    thread.join();
    Throwable newThreadError= errorReference.get();
    if (newThreadError!= null) {
        throw newThreadError;
    }  

The only change is that instead of creating a volatile variable you can use AtomicReference which did same thing behind the scenes.

Solution 11 - Java

Did you play around with setDefaultUncaughtExceptionHandler() and the alike methods of the Thread class? From the API: "By setting the default uncaught exception handler, an application can change the way in which uncaught exceptions are handled (such as logging to a specific device, or file) for those threads that would already accept whatever "default" behavior the system provided."

You might find the answer to your problem there... good luck! :-)

Solution 12 - Java

If you implement Thread.UncaughtExceptionHandler in class that starts the Threads, you can set and then rethrow the exception:

public final class ThreadStarter implements Thread.UncaughtExceptionHandler{

private volatile Throwable initException;

    public void doSomeInit(){
        Thread t = new Thread(){
            @Override
            public void run() {
              throw new RuntimeException("UNCAUGHT");
            }
        };
        t.setUncaughtExceptionHandler(this);

        t.start();
        t.join();

        if (initException != null){
            throw new RuntimeException(initException);
        }

    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        initException =  e;
    }    

}

Which causes the following output:

Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException: UNCAUGHT
	at com.gs.gss.ccsp.enrichments.ThreadStarter.doSomeInit(ThreadStarter.java:24)
	at com.gs.gss.ccsp.enrichments.ThreadStarter.main(ThreadStarter.java:38)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.RuntimeException: UNCAUGHT
	at com.gs.gss.ccsp.enrichments.ThreadStarter$1.run(ThreadStarter.java:15)

Solution 13 - Java

Exception handling in Thread : By default run() method doesn’t throw any exception, so all checked exceptions inside the run method has to be caught and handled there only and for runtime exceptions we can use UncaughtExceptionHandler. UncaughtExceptionHandler is an interface provided by Java to handle exceptions in a Thread run method. So we can implement this interface and set back our implementing class back to Thread object using setUncaughtExceptionHandler() method. But this handler has to be set before we call start() on the tread.

if we don’t set uncaughtExceptionHandler then the Threads ThreadGroup acts as a handler.

 public class FirstThread extends Thread {

int count = 0;

@Override
public void run() {
	while (true) {
		System.out.println("FirstThread doing something urgent, count : "
				+ (count++));
		throw new RuntimeException();
	}

}

public static void main(String[] args) {
	FirstThread t1 = new FirstThread();
	t1.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
		public void uncaughtException(Thread t, Throwable e) {
			System.out.printf("Exception thrown by %s with id : %d",
					t.getName(), t.getId());
			System.out.println("\n"+e.getClass());
		}
	});
	t1.start();
}
}

Nice explanation given at http://coder2design.com/thread-creation/#exceptions

Solution 14 - Java

It is almost always wrong to extend Thread. I cannot state this strongly enough.

Multithreading Rule #1: Extending Thread is wrong.*

If you implement Runnable instead you will see your expected behaviour.

public class Test implements Runnable {

  public static void main(String[] args) {
    Test t = new Test();
    try {
      new Thread(t).start();
    } catch (RuntimeException e) {
      System.out.println("** RuntimeException from main");
    }

    System.out.println("Main stoped");

  }

  @Override
  public void run() {
    try {
      while (true) {
        System.out.println("** Started");

        Thread.sleep(2000);

        throw new RuntimeException("exception from thread");
      }
    } catch (RuntimeException e) {
      System.out.println("** RuntimeException from thread");
      throw e;
    } catch (InterruptedException e) {

    }
  }
}

produces;

Main stoped
** Started
** RuntimeException from threadException in thread "Thread-0" java.lang.RuntimeException: exception from thread
	at Test.run(Test.java:23)
	at java.lang.Thread.run(Thread.java:619)

* unless you want to change the way your application uses threads, which in 99.9% of cases you don't. If you think you are in the 0.1% of cases, please see rule #1.

Solution 15 - Java

My solution with RxJava:

@Test(expectedExceptions = TestException.class)
public void testGetNonexistentEntry() throws Exception
{
    // using this to work around the limitation where the errors in onError (in subscribe method)
    // cannot be thrown out to the main thread
    AtomicReference<Exception> ex = new AtomicReference<>();
    URI id = getRandomUri();
    canonicalMedia.setId(id);

    client.get(id.toString())
        .subscribe(
            m ->
                fail("Should not be successful"),
            e ->
                ex.set(new TestException()));

    for(int i = 0; i < 5; ++i)
    {
        if(ex.get() != null)
            throw ex.get();
        else
            Thread.sleep(1000);
    }
    Assert.fail("Cannot find the exception to throw.");
}

Solution 16 - Java

For those who needs to stop all Threads running and re-run all of them when any one of them is stopped on an Exception:

@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
     
     // could be any function
     getStockHistory();

}


public void getStockHistory() {
        
     // fill a list of symbol to be scrapped
     List<String> symbolListNYSE = stockEntityRepository
     .findByExchangeShortNameOnlySymbol(ContextRefreshExecutor.NYSE);


	storeSymbolList(symbolListNYSE, ContextRefreshExecutor.NYSE);

}


private void storeSymbolList(List<String> symbolList, String exchange) {

	int total = symbolList.size();

    // I create a list of Thread 
	List<Thread> listThread = new ArrayList<Thread>();
	
    // For each 1000 element of my scrapping ticker list I create a new Thread
	for (int i = 0; i <= total; i += 1000) {
		int l = i;

		Thread t1 = new Thread() {

			public void run() {
                
                // just a service that store in DB my ticker list
				storingService.getAndStoreStockPrice(symbolList, l, 1000, 
                MULTIPLE_STOCK_FILL, exchange);

			}

		};
		
	Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
		    public void uncaughtException(Thread thread, Throwable exception) {
		   
                // stop thread if still running
		    	thread.interrupt();

                // go over every thread running and stop every one of them
		    	listThread.stream().forEach(tread -> tread.interrupt());

                // relaunch all the Thread via the main function
		    	getStockHistory();
		    }
		};

		t1.start();
		t1.setUncaughtExceptionHandler(h);
		
		listThread.add(t1);

	}

}

To sum up :

You have a main function that create multiple thread, each of them has UncaughtExceptionHandler which is trigger by any Exception inside of a thread. You add every Thread to a List. If a UncaughtExceptionHandler is trigger it will loop through the List, stop every Thread and relaunch the main function recreation all the Thread.

Solution 17 - Java

You cannot do this, since it doesn't really make sense. If you hadn't called t.join() then you main thread could be anywhere in the code when the t thread throws an exception.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNARUView Question on Stackoverflow
Solution 1 - JavaDan CruzView Answer on Stackoverflow
Solution 2 - JavaabyxView Answer on Stackoverflow
Solution 3 - JavaTalha Ahmed KhanView Answer on Stackoverflow
Solution 4 - JavaPeter LawreyView Answer on Stackoverflow
Solution 5 - Javadenis.solonenkoView Answer on Stackoverflow
Solution 6 - JavaartbristolView Answer on Stackoverflow
Solution 7 - JavaRavindra babuView Answer on Stackoverflow
Solution 8 - JavaJava BeginnerView Answer on Stackoverflow
Solution 9 - JavaAndr1iView Answer on Stackoverflow
Solution 10 - JavaUta AlexandruView Answer on Stackoverflow
Solution 11 - JavaDr. SnugglesView Answer on Stackoverflow
Solution 12 - JavaStefanoView Answer on Stackoverflow
Solution 13 - JavaJatinder PalView Answer on Stackoverflow
Solution 14 - JavaQwerkyView Answer on Stackoverflow
Solution 15 - JavaRomanKoustaView Answer on Stackoverflow
Solution 16 - JavaAntoine VulcainView Answer on Stackoverflow
Solution 17 - JavaMathias SchwarzView Answer on Stackoverflow