线程池中execute和submit的区别

在前阵子的工作中,收到一个bug,大概是在app运行过程中出现了异常,可是查看了app日志、系统日志并没有异常日志打印。最后发现了context.getExternalCacheDir方法返回值为null,原以为bug可以回给系统组的人去修了,在leader的指导下,发现了app中的问题:线程池启动线程的方法为submit,而没有对submit的返回值做处理,在运行过程中也没有catch NPE,任务一直在线程池中错误循环,所以导致了问题,最终将所有线程池的submit方法替换为execute方法,当有未catch的execption时,会直接crash,在系统中打印日志,方便后续的bug处理。

下面说说execute和submit的区别。

首先从源码开始
submit:

public interface ExecutorService extends Executor {
  ...
   Future submit(Callable task);

   Future submit(Runnable task, T result);

  Future submit(Runnable task);
  ...
}

通过源码,submit来源于ExecutorService接口,可以看出,在ExecutorService接口中,一共有以上三个sumbit()方法,入参可以为Callable,也可以为Runnable,而且方法有返回值Future
(补充说明:Callable与Runnable类似,也是创建线程的一种方式,实现其call()方法即可,方法可以有返回值,而且方法上可以抛出异常)

execute:
execute方法来源于Executor接口,上述的ExecutorService接口继承于此,Executor是最上层的,其中只包含一个execute()方法:

public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

总结:
(1)可以接受的任务类型不同
execute只能接受Runnable类型的任务
submit不管是Runnable还是Callable类型的任务都可以接受,但是Runnable返回值均为void,所以使用Future的get()获得的还是null

(2)submit()有返回值,而execute()没有
例如,有个task,希望该task执行完后告诉我它的执行结果,是成功还是失败,然后继续下面的操作,这时需要用submit

(3)submit()可以进行Exception处理
例如,如果task里会抛出checked或者unchecked exception,而你又希望外面的调用者能够感知这些exception并做出及时的处理,那么就需要用到submit,通过对Future.get()进行抛出异常的捕获,然后对其进行处理。

你可能感兴趣的:(线程池中execute和submit的区别)