FutureTask类
FutureTask的实现
public class FutureTask<V> implements RunnableFuture<V> {}
FutureTask类实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现
public interface RunnableFuture<V> extends Runnable, Future<V> { /** * Sets this Future to the result of its computation * unless it has been cancelled. */ void run(); }
public interface RunnableFuture extends Runnable, Future {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
- 当FutureTask处于未启动或已启动状态时,如果此时我们执行FutureTask.get()方法将导致调用线程阻塞;当FutureTask处于已完成状态时,执行FutureTask.get()方法将导致调用线程立即返回结果或者抛出异常。
- 当FutureTask处于未启动状态时,执行FutureTask.cancel()方法将导致此任务永远不会执行。
当FutureTask处于已启动状态时,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果任务取消成功,cancel(...)返回true;但如果执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时cancel(...)返回false。
当任务已经完成,执行cancel(...)方法将返回false。 - FutureTask 构造函数
public FutureTask(Callable<V> callable) { } public FutureTask(Runnable runnable, V result) { }
简单使用案例
在互联网应用中有时候可能数据量会很大会把数据存储在不同的服务器,查询的时候会去查询不通的服务器,然后在把数据汇总,传统查询查完 A 服务器 再去 查询 B 服务然后在汇总,这样可能会导致等带的时间会比较长,使用 future 带返回值得线程就可以很好的解决这样的问题,在查询 A 服务器的同时去查询 B 服务器,最后在把数据汇总,例如
public class ExecutorFutureDemo implements Callable<Integer> { public static void main(String[] args) throws ExecutionException, InterruptedException { long startTime = System.currentTimeMillis(); ThreadPoolExecutor executor = new ThreadPoolExecutor( 1, 1, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); Future<Integer> result = executor.submit(new ExecutorFutureDemo()); System.out.println("开始查询服务器 B ..."); // 保存服务器 B 查询结果 int sum = 0; // 主线程查询服务器 B 的结果 for (int i = 1; i <= 100 ; i++) { sum += i; } // 模拟服务器 B 的查询时间 Thread.sleep(3000); System.out.println("服务器 B 查询完毕。"); if(!result.isDone()){ System.out.println("服务器 A 数数据还没有查询完毕..."); } // 在没有得到结果之前会一直阻塞在这里,直到拿到返回结果 Integer aSum = result.get(); long endTime = System.currentTimeMillis(); System.out.println("查询结果="+(aSum+sum)+",总耗时="+(endTime-startTime)/1000); // 关闭线程池 executor.shutdown(); } @Override public Integer call() throws Exception { System.out.println("开始查询服务器 A ..."); // 保存服务器 A 查询结果 int sum = 0; try { // 模拟服务器 A 的 查询时间 Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 1; i <= 50 ; i++) { sum += i; } System.out.println("服务器 A 查询完毕。"); return sum; } }
结果
开始查询服务器 B ... 开始查询服务器 A ... 服务器 B 查询完毕。 服务器 A 数数据还没有查询完毕... 服务器 A 查询完毕。 查询结果=6325,总耗时= 5 秒
传统查询需要 8 秒,而示例只需要 5 秒即可。