Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java - How can I get a future's stack trace on TimeoutException

In java, I would like to determine the current stack of the thread which populates the result of the future when a TimeoutException occurs. It seems that the top entry in the stack trace provided by a TimeoutException only indicates where future.get() was invoked, not the state of the background thread. For example:

ExecutorService executor = Executors.newSingleThreadExecutor();

Future<String> future = executor.submit(new Callable<String>() {
    @Override
    public String call() throws Exception {
        Thread.sleep(10000);
        return "";
    }
});

try {
    future.get(1, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
    e.printStackTrace();
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}

In this example I've found that the top entry is the future.get(1, TimeUnit.MILLISECONDS) entry, not the Thread.sleep(10000). I would like the stack trace to indicate Thread.sleep(10000) since this is what is currently being executed. Is there an elegant way of doing this?

I've found that if there is an actual execution problem, then the ExecutionException.printStackTrace() will indicate where the problem occurred in the background thread.

like image 856
lots_of_questions Avatar asked Dec 18 '14 18:12

lots_of_questions


People also ask

How can I get the current stack trace in Java?

You can obtain a stack trace from a thread – by calling the getStackTrace method on that Thread instance. This invocation returns an array of StackTraceElement, from which details about stack frames of the thread can be extracted.

How do I print a stack trace?

Another way to print stack trace is using the printStackTrace() method of the Throwable class. Just use new Throwable(). printStackTrace() method and it will print complete stack trace from where a method is called, into the console.

What is Java stack trace?

The stack trace, also called a backtrace, consists of a collection of stack records, which store an application's movement during its execution. The stack trace includes information about program subroutines and can be used to debug or troubleshoot and is often used to create log files.


1 Answers

If you had a reference, t, to the Thread was running the task, you could call t.getStackTrace(); but the standard library ExecutorService implementations aren't going to tell you what thread is running the task.

You could have the task itself record what thread is running it:

class MyTask implements Callable<String> {
    private volatile Thread executorThread;

    @Override
    String call() {
        executorThread = Thread.currentThread(); // not getCurrentThread()
        Thread.sleep(10000);
        return "";
    }

    Thread getExecutorThread() {
        return executorThread;
    }
}

That way, when your main thread times out, it could call myTask.getExecutorThread().getStackTrace();

...
MyTask myTask = new MyTask();
Future<String> future = executor.submit(myTask);
...
} catch (InterruptedException | ExecutionException e) {
    StackTraceElement[] stack = myTask.getExecutorThread().getStackTrace();
    for (StackTraceElement element : stack) {
        ...print it...
    }
}
like image 109
Solomon Slow Avatar answered Oct 12 '22 12:10

Solomon Slow