为什么ScheduledExecutorService不打印堆栈跟踪?

时间:2012-10-15 13:11:55

标签: java exception-handling scheduled-tasks

为什么我们在这个例子中看不到堆栈跟踪?

public class NoStackTraceTester implements Runnable  {
    private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    private ScheduledFuture<?> lifeCheckFuture;

    @Override
    public void run() {
        lifeCheckFuture = startLifecheck();
    }

    private ScheduledFuture<?> startLifecheck()
    {
        Runnable lifeCheck = new Runnable()
        {
            @Override
            public void run()
            {
                System.out.println("sending lifecheck ...");
                throw new RuntimeException("bang!");
            }
        };
        return scheduler.scheduleAtFixedRate(lifeCheck, 1000, 1000, TimeUnit.MILLISECONDS);
    }

    public static void main(String[] args) {
        new NoStackTraceTester().run();
    }
}

如果您尝试对异常进行注释,那么您将执行lifecheck函数的重复任务。 但是如果抛出异常,则线程停止但没有细节:(

你知道为什么吗?

3 个答案:

答案 0 :(得分:3)

ExecutorService将任何捕获的Throwable放置在Future对象中。如果你检查这个,你可以看到抛出了什么异常。这并不总是令人满意的,因此您可能必须在run()方法中捕获并处理或记录任何异常。

注意:一旦异常逃脱,任务不会再次重复。

Runnable lifeCheck = new Runnable() {
    @Override
    public void run() {
        try {
            System.out.println("sending lifecheck ...");
            throw new RuntimeException("bang!");
        } catch(Throwable t) {
            // handle or log Throwable
        }
    }
};

答案 1 :(得分:1)

如果您需要异常报告,则必须自行插入处理代码。 ExecutorService不会自动将异常跟踪发送到标准输出,并且它不是很好,因为这很少是生产代码中我们需要的。

基本上,这就是方法:

public void run()
{
   try {
     System.out.println("sending lifecheck ...");
     throw new RuntimeException("bang!");
   } catch (Throwable t) { t.printStackTrace(); }
}

答案 2 :(得分:0)

ThreadPoolExecutor中的afterExecute()方法可以被覆盖:

class MyThreadPoolExecutor extends ThreadPoolExecutor {
    public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
            TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    @Override
    public void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        // If submit() method is called instead of execute()
        if (t == null && r instanceof Future<?>) {
            try {
                Object result = ((Future<?>) r).get();
            } catch (CancellationException e) {
                t = e;
            } catch (ExecutionException e) {
                t = e.getCause();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        if (t != null) {
            // Exception occurred
            System.err.println("Uncaught exception is detected! " + t
                    + " st: " + Arrays.toString(t.getStackTrace()));
        }
        // ... Perform cleanup actions
    }
}

final class MyTask implements Runnable {
    @Override public void run() {
        System.out.println("My task is started running...");
        // ...
        throw new ArithmeticException(); // uncatched exception
        // ...
    }
}

public class ThreadPoolExecutorHandler {
    public static void main(String[] args) {
        // Create a fixed thread pool executor
        ExecutorService threadPool = new MyThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>());
        threadPool.execute(new MyTask());
        // ...
    }
}

源:https://medium.com/@aozturk/how-to-handle-uncaught-exceptions-in-java-abf819347906(请注意,我修改了此处发布的代码,使其不再执行,因为该问题仅要求进行堆栈跟踪打印)