目录

1.Future 的作用

2.Callable 和 Future 的关系

3.Future 的方法和用法

1.get() 方法:获取结果

2.isDone() 方法:判断是否执行完毕

3.cancel 方法:取消任务的执行

4.isCancelled() 方法:判断是否被取消

4.用 FutureTask 来创建 Future


1.Future 的作用

Future 最主要的作用是,比如当做一定运算的时候,运算过程可能比较耗时,有时会去查数据库,或是繁重的计算,比如压缩、加密等,在这种情况下,如果我们一直在原地等待方法返回,显然是不明智的,整体程序的运行效率会大大降低。我们可以把运算的过程放到子线程去执行,再通过 Future 去控制子线程执行的计算过程,最后获取到计算结果。这样一来就可以把整个程序的运行效率提高,是一种异步的思想。

2.Callable 和 Future 的关系

Callable 接口相比于 Runnable 的一大优势是可以有返回结果。

可以用 Future 类的 get 方法来获取 。因此,Future 相当于一个存储器,它存储了 Callable 的 call 方法的任务结果。

除此之外,我们还可以通过 Future 的 isDone 方法来判断任务是否已经执行完毕了,还可以通过 cancel 方法取消这个任务,或限时获取任务的结果等。

3.Future 的方法和用法

Future 接口的代码,一共有 5 个方法。

public interface Future<V> {boolean cancel(boolean mayInterruptIfRunning);boolean isCancelled();boolean isDone();V get() throws InterruptedException, ExecutionException;V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutExceptio
}

1.get() 方法:获取结果

  • get 方法最主要的作用就是获取任务执行的结果,该方法在执行时的行为取决于 Callable 任务的状态,可能会发生以下 5 种情况。

    • (1)最常见的就是当执行 get 的时候,任务已经执行完毕了,可以立刻返回,获取到任务执行的结果。
    • (2)任务还没有结果,这是有可能的,比如我们往线程池中放一个任务,线程池中可能积压了很多任务,还没轮到我去执行的时候,就去 get 了,在这种情况下,相当于任务还没开始;还有一种情况是任务正在执行中,但是执行过程比较长,所以我去 get 的时候,它依然在执行的过程中。无论是任务还没开始或在进行中,我们去调用 get 的时候,都会把当前的线程阻塞,直到任务完成再把结果返回回来。
    • (3)任务执行过程中抛出异常,一旦这样,我们再去调用 get 的时候,就会抛出 ExecutionException 异常,不管我们执行 call 方法时里面抛出的异常类型是什么,在执行 get 方法时所获得的异常都是 ExecutionException。
    • (4)任务被取消了,如果任务被取消,我们用 get 方法去获取结果时则会抛出 CancellationException。
    • (5)任务超时,我们知道 get 方法有一个重载方法,那就是带延迟参数的,调用了这个带延迟参数的 get 方法之后,如果 call 方法在规定时间内正常顺利完成了任务,那么 get 会正常返回;但是如果到达了指定时间依然没有完成任务,get 方法则会抛出 TimeoutException,代表超时了。

代码样例:

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.*;/*** @author cf* @description: FutureDemo* @date 2023/3/17下午 2:46*/
public class FutureDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService service = Executors.newFixedThreadPool(10);Map<String,Object> params = new HashMap<>();params.put("name",1111);Future<Integer> future = service.submit(new CallableTask(params));System.out.println(future.get());service.shutdown();}static class CallableTask implements Callable<Integer> {private Map<String, Object> params;public CallableTask(Map<String, Object> params) {this.params = params;}@Overridepublic Integer call() throws Exception {System.out.println("参数:"+params.get("name"));Thread.sleep(3000);return new Random().nextInt();}}
}

2.isDone() 方法:判断是否执行完毕

该方法是用来判断当前这个任务是否执行完毕了。

这个方法如果返回 true 则代表执行完成了;如果返回 false 则代表还没完成。但这里如果返回 true,并不代表这个任务是成功执行的,比如说任务执行到一半抛出了异常。那么在这种情况下,对于这个 isDone 方法而言,它其实也是会返回 true 的,因为对它来说,虽然有异常发生了,但是这个任务在未来也不会再被执行,它确实已经执行完毕了。所以 isDone 方法在返回 true 的时候,不代表这个任务是成功执行的,只代表它执行完毕了。

案例:

package thread;import java.util.concurrent.*;/*** @author cf* @description: FutureException* @date 2023/3/17下午 2:59*/
public class FutureException {public static void main(String[] args) {ExecutorService service = Executors.newFixedThreadPool(20);Future<Integer> future = service.submit(new CallableTask());try {for (int i = 0; i < 5; i++) {System.out.println(i);Thread.sleep(500);}System.out.println(future.isDone());future.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}static class CallableTask implements Callable<Integer> {@Overridepublic Integer call() throws Exception {throw new IllegalArgumentException("Callable抛出异常");}}
}

结果:

0
1
2
3
4
true
java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: Callable抛出异常at java.util.concurrent.FutureTask.report(FutureTask.java:122)at java.util.concurrent.FutureTask.get(FutureTask.java:192)at thread.FutureException.main(FutureException.java:21)
Caused by: java.lang.IllegalArgumentException: Callable抛出异常at thread.FutureException$CallableTask.call(FutureException.java:34)at thread.FutureException$CallableTask.call(FutureException.java:30)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at java.lang.Thread.run(Thread.java:748)

这段代码证明了三件事情:

  • 第一件事情,即便任务抛出异常,isDone 方法依然会返回 true;
  • 第二件事情,虽然抛出的异常是 IllegalArgumentException,但是对于 get 而言,它抛出的异常依然是 ExecutionException;
  • 第三个事情,虽然在任务执行一开始时就抛出了异常,但是真正要等到我们执行 get 的时候,才看到了异常。

3.cancel 方法:取消任务的执行

如果不想执行某个任务了,则可以使用 cancel 方法,会有以下三种情况:

  • 第一种情况最简单,那就是当任务还没有开始执行时,一旦调用 cancel,这个任务就会被正常取消,未来也不会被执行,那么 cancel 方法返回 true。
  • 第二种情况也比较简单。如果任务已经完成,或者之前已经被取消过了,那么执行 cancel 方法则代表取消失败,返回 false。因为任务无论是已完成还是已经被取消过了,都不能再被取消了。
  • 第三种情况比较特殊,就是这个任务正在执行,这个时候执行 cancel 方法是不会直接取消这个任务的,而是会根据我们传入的参数做判断。cancel 方法是必须传入一个参数,该参数叫作  mayInterruptIfRunning,它是什么含义呢?

    • 如果传入的参数是 true,执行任务的线程就会收到一个中断的信号,正在执行的任务可能会有一些处理中断的逻辑,进而停止,这个比较好理解。
    • 如果传入的是 false 则就代表不中断正在运行的任务,也就是说,本次 cancel 不会有任何效果,同时 cancel 方法会返回 false。

第三种那么如何选择传入 true 还是 false 呢?

  • 传入 true 适用的情况是,明确知道这个任务能够处理中断。

传入 false 适用于什么情况呢?

  • 如果我们明确知道这个线程不能处理中断,那应该传入 false。
  • 我们不知道这个任务是否支持取消(是否能响应中断),因为在大多数情况下代码是多人协作的,对于这个任务是否支持中断,我们不一定有十足的把握,那么在这种情况下也应该传入 false。

    如果这个任务一旦开始运行,我们就希望它完全的执行完毕。在这种情况下,也应该传入 false。

    这就是传入 true 和 false 的不同含义和选择方法。

4.isCancelled() 方法:判断是否被取消

最后一个方法是 isCancelled 方法,判断是否被取消,它和 cancel 方法配合使用,比较简单。

4.用 FutureTask 来创建 Future

除了用线程池的 submit 方法会返回一个 future 对象之外,同样还可以用 FutureTask 来获取 Future 类和任务的结果。

FutureTask 首先是一个任务(Task),然后具有 Future 接口的语义,因为它可以在将来(Future)得到执行的结果。

FutureTask 的代码实现:

public class FutureTask<V> implements RunnableFuture<V>{...
}

可以看到,它实现了一个接口,这个接口叫作 RunnableFuture。我们再来看一下 RunnableFuture 接口的代码实现:

public interface RunnableFuture<V> extends Runnable, Future<V> {void run();
}

它们的关系如下图所示:

既然 RunnableFuture 继承了 Runnable 接口和 Future 接口,而 FutureTask 又实现了 RunnableFuture 接口,所以 FutureTask 既可以作为 Runnable 被线程执行,又可以作为 Future 得到 Callable 的返回值。

典型用法是,把 Callable 实例当作 FutureTask 构造函数的参数,生成 FutureTask 的对象,然后把这个对象当作一个 Runnable 对象,放到线程池中或另起线程去执行,最后还可以通过 FutureTask 获取任务执行的结果。

案例:

package thread;import java.util.concurrent.*;/*** @author cf* @description: FutureTaskDemo* @date 2023/3/17下午 3:41*/
public class FutureTaskDemo {public static void main(String[] args) {Task task = new Task();FutureTask<Integer> integerFutureTask = new FutureTask<>(task);ExecutorService service = Executors.newFixedThreadPool(20);service.submit(integerFutureTask);try {System.out.println("task运行结果:" + integerFutureTask.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}
}class Task implements Callable<Integer> {@Overridepublic Integer call() throws Exception {System.out.println("子线程正在计算");int sum = 0;for (int i = 0; i < 100; i++) {sum += i;}return sum;}
}

代码首先创建了一个实现了 Callable 接口的 Task,然后把这个 Task 实例传入到 FutureTask 的构造函数中去,创建了一个 FutureTask 实例,并且把这个实例当作一个 Runnable 放到 线程池中去执行,最后再用 FutureTask 的 get 得到结果,并打印出来。

17.Future 介绍与主要用法相关推荐

  1. html图片标签img的介绍以及基本用法详解

    <img> 元素向网页中嵌入一幅图像.<img> 标签有两个必需的属性:src 属性 和 alt 属性. 必需的属性 属性 值 描述 alt text 规定图像的替代文本. s ...

  2. jQuery框架的介绍以及基本用法--操作dom

    jQuery框架的介绍以及基本用法–操作dom 概念 jQuery是一个优秀的javascript轻量级框架之一,兼容css3和各大浏览器,提供了dom,events,animate,ajax等简易操 ...

  3. java中dynamic_介绍@dynamic的用法

    介绍@dynamic的用法 Objective-C 2.0提供了属性(@property),可以让编译器自动生成setter和getter方法.如果不想编译器自作主张生成这些setter和getter ...

  4. Netty5的例子,简单介绍Netty的用法

    转自:http://blog.csdn.net/tjbsl/article/details/51038947 这是一个netty快速入门的例子,也是我的学习笔记,比较简单,翻译于官方的文档整理后把所有 ...

  5. shell介绍及基本用法

    8.1:shell介绍: shell是一个命令解释器,提供用户和机器之间的交互,支持特定语法,支持逻辑判断.循环,并且每个用户都可以有自己的shell: Centos默认的shell是bash(Bou ...

  6. 求介绍matlab函数用法的书,MATLAB初学者教程--函数用法的简单介绍

    1.4 函数用法的简单介绍 1.4.1什么是函数 似乎很多人一听到函数这个词就会想到数学中的某个概念,然后对于恐惧数学的同学就开始打退堂鼓.在matlab当中到处可以用到函数,它的出现可以让我们用很简 ...

  7. django之ORM介绍与基本用法(一)

    文章目录 ORM介绍 ORM用法 字段类型: 字段选项: 关系字段类型 元选项: 模型成员 Manager:管理器类 自定义管理器类:1.修改原始查询集 自定义管理器类:2.新增管理器方法 ORM介绍 ...

  8. POCO C++ Libraies介绍及常见用法

    POCO C++ Libraies属于功能广泛.轻量级别的开源框架库,它拥有媲美Boost库的功能以及较小的体积广泛应用在物联网平台.工业自动化等领域. POCO C++ Libraies由多个功能模 ...

  9. JAVA 17版本介绍(一)安装环境介绍

    为什么笔者会写这篇文章,主要还是Java更新支持来说.首先我们要知道LTS版本JDK和普通JDK的区别. (LTS版本,Long-Term-Support),Java 大版本周期变化后的长期支持版本. ...

最新文章

  1. Java报表工具技巧--如何在Style Report创建用户自定义报表模板
  2. 一个实验教会你配置IPv6地址
  3. opencv vs2013开发环境配置
  4. Lambda表达式替代匿名方法
  5. [NOTE] DSVW靶场练习笔记
  6. 这 4 款实用小工具,能让你的电脑变得好用又骚气
  7. 华为什么时候更新鸿蒙os,华为鸿蒙系统升级时间表
  8. php中用for循环制作矩形,PHP中for循环语句的几种变型
  9. 从outside对ASA防火墙身后ACS4.x进行管理测试
  10. java 判断当前时间是否为节假日_浅谈Java8日期时间处理
  11. 海龟交易法则05_掌握优势
  12. E: Problem executing scripts APT::Update::Post-Invoke-Success 'if /usr/bin/t
  13. 计算机英语会话实用电脑英语,计算机英语会话(MP3+中英字幕) 第41期:实用电脑英语...
  14. 进击系列2.0:进击的骑士-----用funcode与C语言实现射击游戏制作
  15. 西门子224XP源码,包括pcb,原理图,224xp源码
  16. 创建数据库索引的几种方法
  17. 【谷歌重磅发布2017学术影响因子】AI、视觉、机器人TOP20 榜单
  18. win10 提升administrator权限 管理员权限
  19. “2019年新出的境外云闪付是什么?
  20. 第一章 老虎Linux简介

热门文章

  1. CrownCAD三维CAD绘制四连杆机构的具体步骤
  2. 面试/笔试第三弹 —— 数据库面试问题集锦
  3. react 组件渲染控制
  4. 如何获取广告服务流量变现数据,助力广告效果分析?
  5. nvcc fatal : Unsupported gpu architecture ‘compute_86‘
  6. 布法罗大学计算机硕士学费,美国水牛城大学学费贵不贵(美国水牛城大学往年排名情况怎么样)...
  7. python中常见的三种选择结构_在Python中,实现多分支选择结构的最佳方法是
  8. Yii Criteria
  9. 前端 - html2canvas 截图显示空白
  10. C语言学习1——第一、二、三章学习记录