现在可以来记录AbstractExecutorService的异步任务提交了,单刀直入吧,先看三个submit方法提交单个任务:
public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); RunnableFuture<Object> ftask = newTaskFor(task, null); execute(ftask); return ftask; } 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; } public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; }
有了上一篇铺垫很好理解,首先将Runnable或Callable任务包装成RunnableFuture ftask,然后就交给execute(ftask)方法,接着就马上返回ftask。这个execute(Runnable)方法将在子类ThreadPoolExecutor中实现,这里先不着急,看下这个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 <tt>Executor</tt> 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);
在将来某个时刻执行给定的任务command,说明这个方法是将来会去执行,在主线程(submit方法)中是不会阻塞的。另外,注意到如果提交的是Runnable接口,返回的future对象中其结果是在任务提交时候就指定了的,要么是null,要么是T result。上面的分析可以简单测试下:
//Callable 任务 class CallabelTask implements Callable<String>{ String name; public CallabelTask(String name){ this.name = name; } @Override public String call() throws Exception { System.out.println("Start to execute the task " + name); TimeUnit.SECONDS.sleep(5); return name + " is done!"; } }
//测试提交 Callable 任务
public static void submitCallableTask()throws Exception{ ExecutorService executor = Executors.newCachedThreadPool(); List<Future<String>> results = new ArrayList<Future<String>>(5); for(int i = 0; i < 5; ){ results.add(executor.submit(new CallabelTask("task_"+(++i)))); } System.out.println("All the tasks have been submited through invokeAll method!"); executor.shutdown(); for(Future<String> f : results) System.out.println(f.get()); }
submitCallableTask() 调用结果:
public static void main(String[] args) throws Exception { submitCallableTask(); } //调用submitCallableTask的结果: All the tasks have been submited through invokeAll method! Start to execute the task task_1 Start to execute the task task_5 Start to execute the task task_3 Start to execute the task task_4 Start to execute the task task_2 task_1 is done! task_2 is done! task_3 is done! task_4 is done! task_5 is done!
从返回的结果看,主线程在执行完executor.submit(new CallabelTask("task_"+(++i))) 之后并没有阻塞,而是继续往下执行println语句打印出语句:
All the tasks have been submited through invokeAll method!
而提交的任务将由其他线程在“将来某个时刻“去执行。当然在主线程去获取执行结果f.get() 的时候肯定是要阻塞的,因为既然要获取结果了,当然要等到任务执行完毕返回才有啊!
如果把上面的CallabelTask改变成RunnableTask,则返回的结果将是null,原因是提交的时候在new TaskFor方法中就已经指定了返回结果为null:
class RunnableTask implements Runnable{ String name; public RunnableTask(String name){ this.name = name; } @Override public void run() { System.out.println("Start to execute the task " + name); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } } } //RunnableTask 执行结果: All the tasks have been submited through invokeAll method! Start to execute the task task_1 Start to execute the task task_5 Start to execute the task task_3 Start to execute the task task_4 Start to execute the task task_2 null null null null null