更多内容,前往IT-BLOG

一、什么是 Future和 FutureTask


FutureTask 的 Future就源自于它的异步工作机制,如果我们在主线程中直接写一个函数来执行任务,这是同步的任务,也就是说必须要等这个函数返回以后我们才能继续做接下的事情,但是如果这个函数返回的结果对接下来的任务并没有意义,那么我们等在这里是很浪费时间的,而 FutureTask就提供了异步返回结果的机制,当执行一个 FutureTask任务的时候,系统可以接着做别的任务,在将来某个时间,FutureTask任务完成后会返回 FutureTask对象来包装返回的结果,只要调用这个对象的 get()方法即可获取返回值。当然多线程中继承 ThreadPoolExecutor和实现 Runnable也可以实现异步工作机制,可是他们没有返回值。这时可以使用 FutureTask包装 Runnable或者 Callable对象,再使用 FutureTask来执行任务。

Future接口和其唯一的实现类 FutureTask类一般用于表示异步计算的结果。Future接口下提供方法来检查计算是否完成,等待其完成,并检索计算结果。 结果只能在计算完成后使用get() 进行检索,如有必要可进行阻塞,直到准备就绪。 取消由 cancel方法执行,isCancelled方法用于检测计算是否被取消,isDone方法用于检测计算是否完成。 提供其他方法来确定任务是否正常完成或被取消。

二、FutureTask 的使用


根据 FutureTask被执行的进度,FutureTask对象共有3种状态:
【1】未启动:创建了一个 FutureTask对象但没有执行 futureTask.run();
【2】已启动:futureTask.run()方法正在执行;
【3】已完成:futureTask.run()正常执行结束,或者 futureTask被取消(futureTask.cancel()),或者执行 futureTask.run()时抛出异常而异常结束;

FutureTask 的启动


FutureTask实现了 Future接口和 Runnable接口,因此 FutureTask对象的执行有两种方式:

【1】交给线程池的 execute() 或 submit() 执行;

 1 import java.util.concurrent.*;
2 import static java.util.concurrent.TimeUnit.MILLISECONDS;
3
4
5 class test{
6 public static void main(String[] args) throws InterruptedException {
7 ThreadPoolExecutor tpe = new ThreadPoolExecutor(5, 10,100, MILLISECONDS, new ArrayBlockingQueue<Runnable>(5));
8 //用FutureTask包装Runnable或者Callable对象
9 FutureTask<String> future = new FutureTask<String>(new Callable<String>() {
10 @Override
11 public String call() {
12 try{
13 String a = "return String";
14 return a;
15 }
16 catch(Exception e){
17 e.printStackTrace();
18 return "exception";
19 }
20 }
21 });
22 //交给线程池的Execute或submit方法执行
23 tpe.submit(future);
24 try{
25 System.out.println(future.get());
26 }
27 catch(Exception e){
28 e.printStackTrace();
29 }
30 finally{
31 tpe.shutdown();
32 }
33 }
34 }

FutureTask是一个基于AQS同步队列实现的一个自定义同步组件,通过对同步状态 state的竞争实现 acquire或者 release操作。FutureTask 的内部类 Sync实现了 AQS接口,通过对 tryAcquire等抽象方法的重写和模板方法的调用来实现内部类 Sync的 tryAcquireShared等方法,然后聚合 Sync的方法来实现 FutureTask的get,cancel等方法;

FutureTask的 get方法最终会调用 AQS.acquireSharedInterruptibly方法,这个方法操作成功的条件是同步状态为 RAN或者 CANCELLED,也就是说如果这个 FutureTask有线程E正在执行,那么这个 FutureTask的状态是 RUN,因此 AQS.acquireSharedInterruptibly方法调用失败,此时调用 get方法的线程被阻塞,添加到等待队列中(如下图线程D,其中A,B,C是已经被阻塞添加到等待队列中的线程)。当前面执行 FutureTask的线程E执行完毕,那么以原子方式更新同步状态 state的值为RAN,并执行 AQS.release方法,然后唤醒等待队列中的第一个节点中的线程A,此时线程A出队列获得同步状态,并原子设置 state为 RUN,当线程A执行完毕,把 state原子更新为 RUN,然后唤醒线程B,以此类推,因此对于 FutureTask,同一时间只有一个线程执行这个任务。

四、FutureTask使用场景


当一个线程需要等待另一个线程把某个任务执行完以后它才能继续执行时;

有若干线程执行若干任务,每个任务最多只能被执行一次;

当多个线程试图执行同一个任务,但只能允许一个线程执行此任务,其它线程需要等这个任务被执行完毕以后才能继续执行时;

FutureTask 类的更多相关文章

  1. Java并发编程:Future接口、FutureTask类

    在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需要获取执行结果,就 ...

  2. FutureTask类

    FutureTask类是Future 的一个实现,并实现了Runnable. 所以可通过Executor(线程池)来运行,也可传递给Thread对象运行.  假设在主线程中须要运行比較耗时的操作时.但 ...

  3. Future接口和FutureTask类【FutureTask实现了Runnable和Future接口】

    Future API: public interface Future<V> { /** * Attempts to cancel execution of this task. This ...

  4. 并发系列(二)——FutureTask类源码简析

    背景 本文基于JDK 11,主要介绍FutureTask类中的run().get()和cancel() 方法,没有过多解析相应interface中的注释,但阅读源码时建议先阅读注释,明白方法的主要的功 ...

  5. java 多线程:Callable接口;FutureTask类实现对象【Thread、Runnable、Callable三种方式实现多线程的区别】

    Callable接口介绍: Java5开始,Java提供了Callable接口,像是Runnable接口的增强版,Callable接口提供了一个 call()方法可以作为线执行体. call()方法比 ...

  6. FutureTask类的get方法如何实现线程同步等待

    接上篇JDK中线程中实现同步等待闭环的一种方式 - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com),为什么使用了FutureTask中的get方法就可以实现线程的同步等待?这就将重点讲述下F ...

  7. Executor框架(七)Future 接口、FutureTask类

    Future接口介绍   Future 表示异步计算的结果.它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果.   Future 一般由 ExecutorService 的submi ...

  8. ThreadLocal类,实例测试,FutureTask类,实例测试。

    1:测试ThreadLocal类,  为每个线程域保存局部变量.例如下面的例子. ThreadLocal为每个线程保存了一个Test对象,  那么当执行线程时,每个线程中的test具有唯一性.某一个线 ...

  9. Java多线程类FutureTask源码阅读以及浅析

    FutureTask是一个具体的实现类,实现了RunnableFuture接口,RunnableFuture分别继承了Runnable和Future接口,因此FutureTask类既可以被线程执行,又 ...

  10. Java并发编程:Callable、Future和FutureTask

    作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...

随机推荐

  1. 兼容url传参

    //兼容url传参            if(java.nio.charset.Charset.forName("ISO-8859-1").newEncoder().canEnc ...

  2. Day16-异常

    异常机制 一.Error和Exception 1.什么是异常 2.异常体系结构 3.Error和Exception Error Exception 二.捕获和抛出异常 1.异常处理机制 抛出异常 捕获 ...

  3. centos8 安装 spdk

    1. 下载 2.配置 ./configure --enable-debug --disable-tests --without-isal --without-ocf  --with-uring --w ...

  4. mermaid工具

    mermaid支持:流程图.时序图.甘特-等图表的绘制:可在线编辑,保存代码.图片. mermaid :官网.在线编辑器.操作手册

  5. Mac截网页长屏的方法-谷歌浏览器

    打开chrome,左上角帮助,输入[开发者工具],回车,右边显示出一些html代码, 然后shift+command+p: 输入full,选择第一个capture full size screensh ...

  6. Windows,easygui 安装

    在官网下载了easygui,但是根据网上的方法解压后将 easygui 文件夹(创建文件:easygui,只放easygui.py)放到Python36\Lib\site-packages下不行,有模 ...

  7. Jetpack compose学习笔记之ConstraintLayout(布局)

    一,简介 Jetpack compose中没有提供ConstraintLayout支持,所以需要添加下面的依赖来导入. // build.gradle implementation "and ...

  8. FPGA串口 波特率的计数器值

    开发板时钟为50Mhz, t为 20ns; xxx波特率时指每秒传xxx bit字节数据.也就是T=1/xxx; 再用T/t就可以得出波特率的计数周期了: 例如9600:T=1/96000=1.041 ...

  9. Mysql的驱动表 被驱动表 join buffer

    1.为什么小表驱动大表: for(int i=5;.......){     for(int j=1000;......)     {}} 1.1如果小的循环在外层,对于数据库连接来说就只连接5次,进 ...

  10. matlab/simulink中的执行顺序问题

    关于在simulink中开发一些硬件环境模型,有时候会碰到一些模块的执行先后顺序问题.比如说在一个通过UDP发送指令命令给客户端,要求发送的指令有先后的时间顺序,只有在前一条命令发送完以后,才可以进行 ...