Executor框架(七)Future 接口、FutureTask类
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类的更多相关文章
- java并发编程-Executor框架 + Callable + Future
from: https://www.cnblogs.com/shipengzhi/articles/2067154.html import java.util.concurrent.*; public ...
- java集合框架部分相关接口与类的介绍
集合基础 接口 Iterable //Implementing this interface allows an object to be the target of the "for-ea ...
- Java学习笔记33(集合框架七:Collections工具类)
数组有工具类,方面操作数组 集合也有工具类:Collections 常用方法示例: package demo; import java.util.ArrayList; import java.util ...
- java多线程系列(七)---Callable、Future和FutureTask
Callable.Future和FutureTask 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量 ...
- 详解Executor框架
在Java中,使用线程来异步执行任务.Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源.同时,为每一个任务创建一个新线程来执行 ...
- Executor框架学习笔记
Java中的线程即是工作单元也是执行机制,从JDK 5后,工作单元与执行机制被分离.工作单元包括Runnable和Callable,执行机制由JDK 5中增加的java.util.concurrent ...
- Java 线程池 Executor 框架
在Java中,可以通过new Thread 的方法来创建一个新的线程执行任务,但是线程的创建是非常耗时的,而且创建出来的新的线程都各自运行.缺乏统一的管理,这样的后果是可能导致创建过多的线程从而过度消 ...
- Executor框架(一)Executor框架介绍
Executor框架简介 Executor框架的两级调度模型 在HotSpot VM的线程模型中,Java线程被一对一映射为本地操作系统线程.Java线程启动时会创建一个本地操作系统线程:当Jav ...
- 【Java多线程】Executor框架的详解
在Java中,使用线程来异步执行任务.Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源.同时,为每一个任务创建一个新线程来执行 ...
- 第十章 Executor框架
在Java中,使用线程来异步执行任务.Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源.同时,为每一个任务创建一个新线程来执行 ...
随机推荐
- SPSS教程学习笔记1:K个独立样本秩和检验及多重比较 (转载) (非参数假设检验)
本文地址:http://www.datasoldier.net/archives/173版权声明:本文为原创文章,版权归 数据小兵 所有,欢迎分享本文,转载请保留出处! 方差分析经常会出现不满 ...
- I.MX6 HUAWEI MU609 3G porting
/*************************************************************************** * I.MX6 HUAWEI MU609 3G ...
- CF1093:E. Intersection of Permutations(树状数组套主席树)
题意:给定长度为N的a数组,和b数组,a和b都是1到N的排列: 有两种操作,一种是询问[L1,R1],[L2,R2]:即问a数组的[L1,R1]区间和b数组的[L2,R2]区间出现了多少个相同的数字. ...
- Python中if __name__ == "__main__"详解
比如你编写一个test.py文件,一个python文件就可以看作是一个python的模块,这个python模块(.py文件)有两种使用方式:直接运行使用和作为模块被其他模块调用. 解释下__ ...
- HDU 2111:Saving HDU(贪心)
Saving HDU Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- shell 命令学习
https://blog.csdn.net/mnmlist/article/details/55215158
- day23 python学习 类 人狗大战
面向过程 VS 面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 面向过程 优点是:极大的降低了 ...
- 转 JavaScript中判断对象类型的种种方法
我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...
- oracle 、sql server 、mysql 复制表数据
我们知道在oracle 中复制表数据的方式是使用 create table table_name as select * from table_name 而在sql server 中是不能这么使用的 ...
- RabbitMQ消息可靠性分析
消息中间件的可靠性是指对消息不丢失的保障程度:而消息中间件的可用性是指无故障运行的时间百分比,通常用几个 9 来衡量.不存在绝对的可靠性只能尽量趋向完美.并且通常可靠性也意味着影响性能和付出更大的成本 ...