简体   繁体   中英

Printing the stack trace from a newly created thread when an unchecked exception is thrown in Eclipse

Why am I unable to see the stack trace in Eclipse's console when an unchecked Exception is thrown from a thread different from the main thread?

For example:

ScheduledThreadPoolExecutor scheduledExecutor;
scheduledExecutor.scheduleAtFixedRate(new Log(), 0, LOGGING_FREQUENCY_MS, TimeUnit.MILLISECONDS);
public class Log implements Runnable {
        public void run() {
     //NullPointerException is thrown
     }
}

I get no output. But if I do:

ScheduledThreadPoolExecutor scheduledExecutor;
scheduledExecutor.scheduleAtFixedRate(new Log(), 0, LOGGING_FREQUENCY_MS, TimeUnit.MILLISECONDS);
public class Log implements Runnable {
        public void run() {
        try {
        //NullPointerException is thrown
        }catch(Exception e){
             e.printStackTrace();
        }
    }
}

I can see the stack trace.

Why?

EDIT: Follow-up question: What would be the easiest way to print the exceptions thrown by thread-pool threads? Adding try-catch to every single Runnable is of course really ugly.

Why am I unable to see the stack trace in Eclipse's console when an unchecked Exception is thrown from a thread different from the main thread?

Because it is unchecked. By default there is nothing that prints the exceptions thrown by thread-pool threads.

If you want to see the exception then you need to do something like:

Future future = scheduledExecutor.submit(...);
...
try {
   // wait for the run() method to finish normally or with a throw
   future.get();
} catch (ExecutionException e) {
   // the cause of this exception is the one that is thrown by the run()
   Throwable cause = e.getCause();
   cause.printStackTrace();
}

EDIT: Follow-up question: What would be the easiest way to print the exceptions thrown by thread-pool threads? Adding try-catch to every single Runnable is of course really ugly.

You don't need to add the try/catch to the Runnable , you add it to the guy who starts the pool.

Another solution would be to write a little RunnableWrapper which prints out exceptions:

public void RunnableWrapper implements Runnable {
     private Runnable delegate;
     public RunnableWrapper(Runnable delegate) {
       this.delegate = delegate;
     }
     public void run() {
         try {
            delegate.run();
         } catch (Throwable t) {
             t.printStackTrace();
         }
     }
 }

Then you can do:

 scheduledExecutor.submit(new RunnableWrapper(myTask));

But the future.get(); is the typical way of solving this.

Because the Executor has "swallowed" the exception. You can see if you got one by querying the returned future:

Future<?> f = scheduledExecutor.scheduleAtFixedRate(new Log(),...);
try {
    f.get();
} catch (ExecutionException e) {
    Throwable actualException = e.getCause();
}

Note that f.get() will block until the task is cancelled or throws an exception so you will probably want to call it in a separate thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM