一.概念
Future可获取计算的结果。 它有提供方法来检查计算是否完成,等待其完成,并检索计算结果。 结果只能在计算完成后使用方法get进行检索,如有必要,阻塞,直到准备就绪。 取消由cancel方法执行。 提供其他方法来确定任务是否正常完成或被取消。 计算完成后,不能取消计算。 如果您想使用Future ,以便不可撤销,但不提供可用的结果,则可以声明Future<?>表格的类型,并返回null作为基础任务的结果。
Future模式非常适合在处理很耗时很长的业务逻辑时进行使用,可以有效的减小系统的响应时间,提高系统的吞吐量。
public interface Future<V> { //尝试取消执行此任务。如果任务已经完成,已经被取消或由于某些其他原因而无法取消,则此尝试将失败。 //如果成功,并且在调用 cancel 时此任务尚未开始,则该任务永远无法运行。 //如果任务已经开始,则 mayInterruptIfRunning 参数确定是否应中断执行该任务的线程以尝试停止该任务。 //mayInterruptIfRunning == true, 表示中断执行中的线程,false 表示让线程正常完成 boolean cancel(boolean mayInterruptIfRunning); //如果此任务在正常完成之前被取消,则返回true。 boolean isCancelled(); //如果此任务完成,则返回true。完成可能是由于正常终止,异常或取消引起的,在所有这些情况下,此方法都将返回true。 boolean isDone(); //必要时等待计算完成,然后检索其结果 V get() throws InterruptedException, ExecutionException; //必要时最多等待给定时间以完成计算,然后检索其结果(如果有)。 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
Future是一个接口,提供了方法来检测当前的任务是否已经结束,还可以等待任务结束并且拿到一个结果,通过调用Future的get()方法可以当任务结束后返回一个结果值,如果工作没有结束,则会阻塞当前线程,直到任务执行完毕;可以通过调用cancel()方法来停止一个任务,如果任务已经停止,则cancel()方法会返回true;如果任务已经完成或者已经停止了或者这个任务无法停止,则cancel()会返回一个false。当一个任务被成功停止后,他无法再次执行。isDone()和isCancel()方法可以判断当前工作是否完成和是否取消。
类图结构:
- ScheduledFuture:这个接口表示一个延时的行为可以被取消。通常一个安排好的future是定时任务SchedualedExecutorService的结果;
- RunnableFuture: 这个接口同时继承Future接口和Runnable接口,在成功执行run()方法后,可以通过Future访问执行结果;
- ForkJoinTask:基于任务的抽象类,可以通过ForkJoinPool来执行。一个ForkJoinTask是类似于线程实体,但是相对于线程实体是轻量级的。大量的任务和子任务会被ForkJoinPool池中的真实线程挂起来,以某些使用限制为代价;
- CompletableFuture:一个Future类是显示的完成,而且能被用作一个完成等级,通过它的完成触发支持的依赖函数和行为。当两个或多个线程要执行完成或取消操作时,只有一个能够成功;
- RunnableScheduledFuture:执行延迟和周期性任务;在成功执行run()方法后,可以通过Future访问执行结果;
- FutureTask:可取消的异步计算
- 该类提供了一个Future的基本实现 ,具有启动和取消计算的方法,查询计算是否完整,并检索计算结果。结果只能在计算完成后才能检索; 如果计算尚未完成,则get方法将阻止。一旦计算完成,则无法重新启动或取消计算(除非使用runAndReset()调用计算 );
- FutureTask可用于包装Callable或Runnable对象。 因为FutureTask实现Runnable ,一个FutureTask可以提交到一个Executor执行;
- RecursiveTask:递归结果ForkJoinTask;
- RecursiveAction:递归结果ForkJoinTask;
二.用法
一个场景,我们要学习做饭,那么我们需要准备厨具和食材,厨具通过电子商务网购,食材去菜市场挑选。那么可以使用多线程来并发进行,即我们可以先网购下单,在等待快递员送货过来的这段时间去菜市场买食材,节省时间,提高效率。
- 直接开启线程,使用类继承Thread重写方法实现网购,join阻塞直到厨具到达才开始做饭。
public class FutureTest { public static void main(String[] args) throws InterruptedException { long startTime = System.currentTimeMillis(); OnlineShopping shopping = new OnlineShopping(); shopping.start(); Thread.sleep(2000);//等待送货执行完 System.out.println("第二步:食材到位"); shopping.join();//阻塞订单直到快递送到得到厨具 System.out.println("第三步:开始厨