开发Android APP经常会使用AsyncTask框架来异步加载资源或者异步到服务器拉消息,等任务完成后再主动更新结果到UI主线程,AsyncTask框架可以非常方便的获取线程异步执行结果。Java 5之前,Java 并没有提供API用于查询线程是否执行完毕以及如何获取线程执行的结果;Java 5 之后版本提供的并发框架包java.util.concurrent对多线程提供了更多更好的支持,Future接口和FutureTask类是异步执行任务的框架的重要组成部分,为了更清楚的理解,我们还得从Runnable、Callable、ExecutorService等接口说起。
Runnable接口:instance可以使用new Thread(Runnable r)放到一个新线程中跑,没有返回结果;也可以使用ExecutorService.submit(Runnable r)放到线程池中跑,返回结果为null,等于没有返回结果,但可以通过返回的Future对象查询执行状态。
public abstract void run();
Callable接口:instance只能在ExecutorService的线程池中跑,但有返回结果,也可以通过返回的Future对象查询执行状态。表面上可以把Callable接口简单的理解为有返回结果的Runnalbe接口。
V call() throws Exception;
ExecutorService接口:线程池执行调度框架
<T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task);
Future接口:用于查询任务执行状态,获取执行结果,或者取消未执行的任务。在ExecutorService框架中,由于使用线程池,所以Runnable与Callable实例都当做任务看待,而不会当做“线程”看待,所以Future才有取消任务执行等接口。接口中的get()方法用于获取任务执行结果,因为任务是异步执行的,所以我们可以在需要使用结果的时候才调用get()方法,调用时如果任务还未执行完就会阻塞直到任务完成;当然我们也可以调用get的另一重载版本get(long timeout, TimeUnit unit),当阻塞时会等待指定的时间,如果时间到而任务还未完成,那么就会抛出TimeoutException。
boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
FutureTask类:集Runnable、Callable、Future于一身,它首先实现了Runnable与Future接口,然后在构造函数中还要注入Callable对象(或者变形的Callable对象:Runnable + Result),所以FutureTask类既可以使用new Thread(Runnable r)放到一个新线程中跑,也可以使用ExecutorService.submit(Runnable r)放到线程池中跑,而且两种方式都可以获取返回结果,但实质是一样的,即如果要有返回结果那么构造函数一定要注入一个Callable对象,或者注入一个Runnable对象加一个预先给定的结果(个人觉得这作用不大)。
public interface RunnableFuture<V> extends Runnable, Future<V>{ ...} public class FutureTask<V> implements RunnableFuture<V> { public FutureTask(Callable<V> callable) public FutureTask(Runnable runnable, V result) ... }
示例代码:
package com.stevex.app.forkjoin; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; public class FutureTaskTest { public static void main(String[] args) { Callable<String> c = new Callable<String>() { public String call() { try { TimeUnit.SECONDS.sleep(new Random().nextInt(5)); } catch (InterruptedException e) { e.printStackTrace(); } return "Callable--"+Thread.currentThread().getName(); } }; //seed a single thread FutureTask<String> ft1 = new FutureTask<String>(c); Thread t = new Thread(ft1); t.start(); Runnable r = new Runnable() { public void run() { try { TimeUnit.SECONDS.sleep(new Random().nextInt(5)); } catch (InterruptedException e) { e.printStackTrace(); } } }; FutureTask<String> ft2 = new FutureTask<String>(r, "Runnable");//give return value directly FutureTask<String> ft3 = new FutureTask<String>(c); FutureTask<String> ft4 = new FutureTask<String>(c); FutureTask<String> ft5 = new FutureTask<String>(c); FutureTask<String> ft6 = new FutureTask<String>(c); ExecutorService es = Executors.newFixedThreadPool(2);//init ExecutorService es.submit(ft2); es.submit(ft3); es.submit(ft4); es.submit(ft5); es.submit(ft6); try { TimeUnit.SECONDS.sleep(1); if(ft1.isDone()){ ft4.cancel(false); if(ft4.isCancelled()){ System.out.println("task4 cancelled."); } } if(ft2.isDone()){ ft5.cancel(false); if(ft5.isCancelled()){ System.out.println("task5 cancelled."); } } if(ft3.isDone()){ ft6.cancel(false); if(ft6.isCancelled()){ System.out.println("task5 cancelled."); } } System.out.println("task1 retult:" + ft1.get()); System.out.println("task2 retult:" + ft2.get()); System.out.println("task3 retult:" + ft3.get()); if(! ft4.isCancelled()){ System.out.println("task4 retult:" + ft4.get()); } if(! ft5.isCancelled()){ System.out.println("task5 retult:" + ft5.get()); } if(! ft6.isCancelled()){ System.out.println("task6 retult:" + ft6.get()); } es.shutdown();//shut down ExecutorService } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }