Future接口介绍

  Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。

  Future 一般由 ExecutorService 的submit()、invokeAll()方法返回的,用于跟踪、获取任务在线程池中的运行情况、等待运算结果,还可以取消任务。(还有其子接口 ScheduleFuture 则由 ScheduleExecutorService 的schedule()等方法返回);

方法描述

boolean cancel(boolean mayInterruptIfRunning):

试图取消对此任务的执行。分成以下三种情况:

  • 如果任务尚未启动,则此任务将永不运行。
  • 如果任务已经启动,则 mayInterruptIfRunning 参数确定是否 中断这个任务来尝试停止任务。同时,任务也应该要对中断敏感。
  • 任务已完成、或已取消,或者由于某些其他原因而无法取消,返回false。

注意: 此方法返回后,对 isDone() 的后续调用将始终返回 true。但如果此方法返回 true,则对 isCancelled() 的后续调用才将始终返回

boolean isCancelled(): 如果在任务正常完成前将其取消,则返回 true。

boolean isDone(): 如果任务已完成,则返回 true。 可能由于正常终止、异常或取消而完成,在所有这些情况中,此方法都将返回 true。

获取计算结果

  获取计算结果的方法,JDK提供了两个方法:阻塞获取 与 超时等待获取。这两个方法会抛出 CancellationException(任务被取消时)、InterruptedException

V get(): 等待计算完成,然后获取其结果。

V get(long timeout,TimeUnit unit): 最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。

@ Example 示例

  下面的例子,是在单线程的线程池中提交两个任务(任务A、任务B)。

public class Test {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//单线程的线程池
ExecutorService executor = Executors.newSingleThreadExecutor();
//提交两个任务
Future futureA = executor.submit(new MyCallable("futureA"));
Future futureB = executor.submit(new MyCallable("futureB")); Thread.sleep(1000);
//在运行一秒后,判断任务A是否完成
if(futureA.isDone()){
//如果完成,则直接获取结果
double result = (double) futureA.get();
System.out.println("运算结果是:"+result);
}else{
//如果没有完成,则取消任务A
boolean b = futureA.cancel(false);
System.out.println("futureA 执行了cancel方法,返回的值是:"+b);
}
//取消任务B
futureB.cancel(false);
}
} class MyCallable implements Callable{ String taskName; public MyCallable(String taskName){
this.taskName = taskName;
} @Override
public Object call() {
try {
//模拟任务的执行时间为 2s
for(int i=0;i<5;i++){
Thread.sleep(400);
System.out.println(taskName+"任务正在运行中.....");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
double d = Math.random() * 10;
return d;
}
}

运行结果:

futureA任务正在运行中.....

futureA任务正在运行中.....

futureA 执行了cancel方法,返回的值是:true

futureA任务正在运行中.....

futureA任务正在运行中.....

futureA任务正在运行中.....

  任务A是在执行时被取消的,调用的cancel(false) 方法返回的结果为true,但是任务并没有真的停止执行。任务B则是在还没被执行时取消的,所以任务B在后续的时间内,没有执行。

  可以得出结论,cancel( false)方法是取消尚未被执行的任务、周期任务,而不是停止正在执行的任务。当然,如果想要停止正在执行的任务,任务里面必须是中断敏感,然后 cancel(true),参数为true,即在cancel的同时,也发出中断信号。

//简单的中断处理,发现中断退出
public void run(){
while(!Thread.interrupted()){
//.....
}
}

FutureTask 介绍

  FutureTask 是一个可取消的异步计算任务,是一个独立的类,实现了 Future、Runnable接口。FutureTask 的出现是为了弥补 Thread 的不足而设计的,可以让程序员跟踪、获取任务的执行情况、计算结果

  因为 FutureTask 实现了 Runnable,所以 FutureTaskk 可以作为参数来创建一个新的线程来执行,也可以提交给 Executor 执行。FutureTask 一旦计算完成,就不能再重新开始或取消计算。

构造方法

FutureTask(Callable callable)

创建一个 FutureTask,一旦运行就执行给定的 Callable。

FutureTask(Runnable runnable, V result)

创建一个 FutureTask,一旦运行就执行给定的 Runnable,并安排成功完成时 get 返回给定的结果 。

应用场景

FutureTask 可用于异步获取执行结果或可以取消执行任务的场景;

@ Example 简单例子

  下面的例子中,因为计算数据的时间比较长,所以main线程就额外起一个异步线程来计算数据,从而使得计算数据的同时,main线程可以做其他工作,直到需要用到计算结果时,才去获取计算结果。

  需要注意的是,线程 thread2 并没有执行 FutureTask,因为 FutureTask 已经在线程 thread 中完成了。一旦 FutureTask 计算完成,就不能再重新开始或取消计算。

public class Test {
public static void main(String[] args) throws InterruptedException, ExecutionException {
FutureTask<Double> task = new FutureTask(new MyCallable());
//创建一个线程,异步计算结果
Thread thread = new Thread(task);
thread.start();
//主线程继续工作
Thread.sleep(1000);
System.out.println("主线程等待计算结果...");
//当需要用到异步计算的结果时,阻塞获取这个结果
Double d = task.get();
System.out.println("计算结果是:"+d); //用同一个 FutureTask 再起一个线程
Thread thread2 = new Thread(task);
thread2.start();
}
} class MyCallable implements Callable<Double>{ @Override
public Double call() {
double d = 0;
try {
System.out.println("异步计算开始.......");
d = Math.random()*10;
d += 1000;
Thread.sleep(2000);
System.out.println("异步计算结束.......");
} catch (InterruptedException e) {
e.printStackTrace();
}
return d;
}
}

运行结果:

异步计算开始.......

主线程等待计算结果...

异步计算结束.......

计算结果是:1002.7806590582911

除了实现Future、Runnable外,此类还提供了几个protected方法,用于扩展此类

protected void done()

当此任务转换到状态 isDone(不管是正常地还是通过取消)时,调用受保护的方法。默认实现不执行任何操作。

protected void set(V v)

除非已经设置了此 Future 或已将其取消,否则将其结果设置为给定的值。在计算成功完成时通过 run 方法内部调用此方法。

protected void setException(Throwable t)

除非已经设置了此 Future 或已将其取消,否则它将报告一个 ExecutionException,并将给定的 throwable 作为其原因。在计算失败时通过 run 方法内部调用此方法。

protected boolean runAndReset()

执行计算而不设置其结果,然后将此 Future 重置为初始状态,如果计算遇到异常或已取消,则该操作失败。本操作被设计用于那些本质上要执行多次的任务。

Executor框架(七)Future 接口、FutureTask类的更多相关文章

  1. java并发编程-Executor框架 + Callable + Future

    from: https://www.cnblogs.com/shipengzhi/articles/2067154.html import java.util.concurrent.*; public ...

  2. java集合框架部分相关接口与类的介绍

    集合基础 接口 Iterable //Implementing this interface allows an object to be the target of the "for-ea ...

  3. Java学习笔记33(集合框架七:Collections工具类)

    数组有工具类,方面操作数组 集合也有工具类:Collections 常用方法示例: package demo; import java.util.ArrayList; import java.util ...

  4. java多线程系列(七)---Callable、Future和FutureTask

    Callable.Future和FutureTask 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量 ...

  5. 详解Executor框架

    在Java中,使用线程来异步执行任务.Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源.同时,为每一个任务创建一个新线程来执行 ...

  6. Executor框架学习笔记

    Java中的线程即是工作单元也是执行机制,从JDK 5后,工作单元与执行机制被分离.工作单元包括Runnable和Callable,执行机制由JDK 5中增加的java.util.concurrent ...

  7. Java 线程池 Executor 框架

    在Java中,可以通过new Thread 的方法来创建一个新的线程执行任务,但是线程的创建是非常耗时的,而且创建出来的新的线程都各自运行.缺乏统一的管理,这样的后果是可能导致创建过多的线程从而过度消 ...

  8. Executor框架(一)Executor框架介绍

    Executor框架简介 Executor框架的两级调度模型   在HotSpot VM的线程模型中,Java线程被一对一映射为本地操作系统线程.Java线程启动时会创建一个本地操作系统线程:当Jav ...

  9. 【Java多线程】Executor框架的详解

    在Java中,使用线程来异步执行任务.Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源.同时,为每一个任务创建一个新线程来执行 ...

  10. 第十章 Executor框架

    在Java中,使用线程来异步执行任务.Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源.同时,为每一个任务创建一个新线程来执行 ...

随机推荐

  1. magento如何改变首页的布局

    打开MAGENTO_INSTALLED_DIR/app/design/frontend/default/default/layout/page.xml 找到名字为'root'的block定义 < ...

  2. CentOS7安装OpenStack(Rocky版)-05.安装一个nova计算节点实例

    上一篇文章分享了控制节点的nova计算服务的安装方法,在实际生产环境中,计算节点通常会安装一些单独的节点提供服务,本文分享单独的nova计算节点的安装方法 ----------------  完美的分 ...

  3. C# 使用GZip对字符串压缩和解压

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...

  4. hdu1069 dp

    题意:有若干种不同规格(长.宽.高)的砖块,每种砖块有无数个,可以自由选择以砖块的哪条边做长.宽或高,用这些砖块搭高塔,要求上面砖块的长宽必须严格小于下面砖块的长宽,问塔最高能有多高 我的做法是每读入 ...

  5. 给div加滚动条

    <div style="width:175px;height:100px;background:white;overflow:scroll;"> <span> ...

  6. 来自官方的一些dbt 最佳实践

    限制对原始数据的依赖性 您的项目将取决于存储在数据库中的原始数据.我们建议制作所谓的“基本模型”,以最大限度地减少对原始数据表的依赖性.在此约定中,基本模型可以具有以下职责: 仅选择与当前分析相关的字 ...

  7. 标 题: Re: 总感觉IT没我大山东啥事?

    发信人: liuzhlai (liuzhlai), 信区: ITExpress 标  题: Re: 总感觉IT没我大山东啥事? 发信站: 水木社区 (Sat Aug 22 15:51:50 2015) ...

  8. 【转】每天一个linux命令(42):kill命令

    原文网址:http://www.cnblogs.com/peida/archive/2012/12/20/2825837.html Linux中的kill命令用来终止指定的进程(terminate a ...

  9. RabbitMQ 知识点

    mac下 rabbitmq 安装: brew命令 brew install rabbitmq 注意: rabbitmq的安装目录: /usr/local/Cellar/rabbitmq/3.6.6 r ...

  10. WeakHashMap 理解

    WeakHashMap 通过 expungeStaleEntries 这个函数的来实现:移除其内部不用的条目,从而达到自动释放内存的目的. 基本上只要对 WeakHashMap 的内容进行访问就会调用 ...