在线程池中寻找堆栈

2019-01-02  本文已影响2人  即墨灯火

如果在提交给线程池的任务中抛出了异常,这个异常可能不会打印任何内容,也没有被任何人捕获,形成一个幽灵异常。

为了避免这种危险情况的发生,有以下解决方式

  1. 使用Future与Callable
  2. 对于Runnable,使用execute方法而非submit方法

以上两种方式可以获得异常在哪里抛出,但是仍然丢失了一个重要信息:任务的具体提交位置。

如果想进一步获取上述信息,需要自行扩展ThreadPoolExecutor,使其在调度任务之前,先保存一下提交任务线程的堆栈信息。

扩展:

execute与submit的异同

execute是Executors的接口,submit则是ExecutorService的接口
对于ThreadPoolExecutor而言,其实现了execute,而sumit方法则继承自抽象类AbstractExecutorService

对于submit方法

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask); //AbstractExecutorService未实现execute
    return ftask;
}

/**
* @throws RejectedExecutionException {@inheritDoc}
 * @throws NullPointerException       {@inheritDoc}
*/
public <T> Future<T> submit(Runnable task, T result) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task, result);
    execute(ftask);
    return ftask;
}

/**
 * @throws RejectedExecutionException {@inheritDoc}
 * @throws NullPointerException       {@inheritDoc}
 */
public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}

可以看到,submit事实上封装了一个Future。

因此,对于Runnable而言,应当直接使用execute方法,无需经由submit包装。对于希望获得返回值的Callable,则适合使用submit方法。

参考:
Java 8 源码
《实战Java高并发程序设计》
https://blog.csdn.net/hayre/article/details/53314599

上一篇 下一篇

猜你喜欢

热点阅读