FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。

Callable中有一个call()函数,但是call()函数有返回值,而Runnable的run()函数不能将结果返回给客户程序。Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果。

FutureTask是一个RunnableFuture<V>,RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口。

FutureTask实现Runnable,所以能丢到Thread执行。

FutureTask实现Runnable,所以能丢给ExcecuteService线程池执行,ExcecuteService线程池也是吧任务丢到Thread里面去的。

可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。

Callable 和 Future接口的区别
Callable规定的方法是call(),而Runnable规定的方法是run(). 
Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。  
call()方法可抛出异常,而run()方法是不能抛出异常的只能内部消化。 
运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。 
它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。 
通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。 
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。
Callable和Future、FutureTask配合可以用来获取异步执行的结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。

线程池使用 FutureTask 时候需要注意的一点事,FutureTask 使用不当可能会造成调用线程一直阻塞,如何避免?

线程池使用 FutureTask 的时候如果拒绝策略设置为了 DiscardPolicy和DiscardOldestPolicy并且在被拒绝的任务的 Future 对象上调用无参 get 方法那么调用线程会一直被阻塞。

也就是说当 future 的状态 > COMPLETING 时候调用 get 方法才会返回,而明显 DiscardPolicy 策略在拒绝元素的时候并没有设置该 future 的状态,后面也没有其他机会可以设置该 future 的状态,所以 future 的状态一直是 NEW,所以一直不会返回,同理 DiscardOldestPolicy 策略也是这样的问题,最老的任务被淘汰时候没有设置被淘汰任务对于 future 的状态。

所以当使用 Future 的时候,尽量使用带超时时间的 get 方法,这样即使使用了 DiscardPolicy 拒绝策略也不至于一直等待,等待超时时间到了会自动返回的,如果非要使用不带参数的 get 方法则可以重写 DiscardPolicy 的拒绝策略在执行策略时候设置该 Future 的状态大于 COMPLETING 即可,但是查看 FutureTask 提供的方法发现只有 cancel 方法是 public 的并且可以设置 FutureTask 的状态大于 COMPLETING,重写拒绝策略具体代码可以如下:

public class MyRejectedExecutionHandler implements RejectedExecutionHandler {
public void rejectedExecution(Runnable runnable, ThreadPoolExecutor threadPoolExecutor) {
if (!threadPoolExecutor.isShutdown()) {
if(null != runnable && runnable instanceof FutureTask){
((FutureTask) runnable).cancel(true);
}
}
}
}

run():任务执行之后,设置s=COMPLETING=1原状态不是NEW就不设置,被cancel()改变了),在设置s=NORMAL=2正常完成)。任务执行异常之后,设置s=COMPLETING=1原状态不是NEW就不设置,被cacnel()改变了),再设置s=EXCEPTIONAL=3异常完成).

cancel(): false  NEW0->CANCELLED4     true: NEW0 ->INTERRUPTING5->中断线程->INTERRUPTED6 

会先设置s=INTERRUPTING=5或者s=CANCELLED=4原状态不是NEW就不设置,被run()改变了),设置成功之后,中断线程之后,再设置s=INTERRUPTED=6。(都表示异常了)。

cancel()方法的作用就是改变状态,中断异常,唤醒waiter。影响run()方法设置结果,影响get()awiatDone()获取结果抛出异常。

get():只有在s <= COMPLETING=1才去阻塞拿结果,s>1不阻塞直接去拿结果(结果是null,并且抛出异常)。

get()里面的awaitDone():等待结果时候,s > COMPLETING=1就返回(有可能取消或者异常了,得到的结果是null,并且抛出异常),s == COMPLETING=1就线程让步。

isCancelled():state >= CANCELLED=4

isDone():state != NEW=0

设置1:run()正常,run()异常

设置2:run()正常完成

设置3:run()异常完成

设置4:cancel(false)

设置5:cancel(true)第一步

设置6:cancel(true)中断后最后一步

public class BBD {
public static void main(String[] args) throws Exception { Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("正在下载中...");
return "Hello World!";
}
};
FutureTask1<String> futureTask = new FutureTask1<>(callable);// Callable变成FutureTask
Thread t1 = new Thread(futureTask,"任务正常执行线程");
t1.start();
// new Thread(futureTask).start();//run()方法里面第一个CAS就return了
// new Thread(futureTask).start();//run()方法里面第一个CAS就return了 for (int i = ; i < ; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
futureTask.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
} }, "get()线程" + (i+)).start(); new Thread(new Runnable() {
@Override
public void run() {
try {
futureTask.get(5L,TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
}
} }, "get(5L)线程" + (i+)).start();
} new Thread(new Runnable() {
@Override
public void run() {
futureTask.cancel(true);
} }, "cancel()线程").start(); boolean b = Thread.currentThread().isInterrupted();//cancel(true)会设置中断标记 //-------------------------------------------------------------------------------------------------- Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("正在下载中...");
}
}; FutureTask1<String> runnableTask = new FutureTask1<>(runnable, "我是返回的结果");
new Thread(runnableTask).start();
System.out.println("从网络下载的结果为:" + runnableTask.get());//Runnable没有返回值,这里返回期望值。
}
}

FutureTask源码的更多相关文章

  1. Java 多线程(五)—— 线程池基础 之 FutureTask源码解析

    FutureTask是一个支持取消行为的异步任务执行器.该类实现了Future接口的方法. 如: 取消任务执行 查询任务是否执行完成 获取任务执行结果(”get“任务必须得执行完成才能获取结果,否则会 ...

  2. FutureTask 源码分析

    FutureTask 源码分析,这个类的原理与我分析android当中的FutureTask类差不多[http://www.cnblogs.com/daxin/p/3802392.html] publ ...

  3. FutureTask 源码解析

    FutureTask 源码解析 版权声明:本文为本作者原创文章,转载请注明出处.感谢 码梦为生| 刘锟洋 的投稿 站在使用者的角度,future是一个经常在多线程环境下使用的Runnable,使用它的 ...

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

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

  5. FutureTask源码深度剖析

    FutureTask源码深度剖析 前言 在前面的文章自己动手写FutureTask当中我们已经仔细分析了FutureTask给我们提供的功能,并且深入分析了我们该如何实现它的功能,并且给出了使用Ree ...

  6. Java并发编程笔记之FutureTask源码分析

    FutureTask可用于异步获取执行结果或取消执行任务的场景.通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过Fu ...

  7. FutureTask源码解析

    在Java中一般通过继承Thread类或者实现Runnable接口这两种方式来创建多线程,但是这两种方式都有个缺陷,就是不能在执行完成后获取执行的结果,因此Java 1.5之后提供了Callable和 ...

  8. 并发编程—— FutureTask 源码分析

    1. 前言 当我们在 Java 中使用异步编程的时候,大部分时候,我们都会使用 Future,并且使用线程池的 submit 方法提交一个 Callable 对象.然后调用 Future 的 get ...

  9. Java Future 和 FutureTask 源码Demo

    Future 是一个接口,看源码有Future 和 FutreTask 使用Demo package java.util.concurrent; /** * A <tt>Future< ...

  10. FutureTask源码阅读

    FutureTask功能用法 类结构 源码中详细说明了FutureTask生命周期状态及变化 /** * The run state of this task, initially NEW. The ...

随机推荐

  1. C#进阶之路(八)集合的应用

    集合是我们编程时候常用的类库,本文主要讨论具体每个类型的区别,每个集合对应的时间复杂度.先上一个时间复杂度图: C#集体类型( Collections in C#) 集合是.NET FCL(Frame ...

  2. Java面向对象——相关基本定义

    Java面向对象——相关基本定义 摘要:本文简单介绍了面向对象的编程方式,以及与之有关的一些基本定义. 面向对象 什么是面向对象 面向对象编程是一种对现实世界建立计算机模型的一种编程方法.简称OOP( ...

  3. Windows动态链接库:dll与exe相互调用问题

    本文回顾学习一下Windows动态链接库:dll与exe相互调用问题.一般滴,exe用来调用dll中的类或函数,但是dll中也可以调用exe中的类或函数,本文做一些尝试总结. dll程序: Calcu ...

  4. Kali无法使用Chrome原因及解决方法

      Kali安装好后,默认的浏览器是Firefox-ESR(Extended Support Release 长期支持)版本.   作为Chrome的死忠粉,当然是要下Chrome用用的.   直到我 ...

  5. STP:生成树协议解决网络冗余问题

    STP(Spanning Tree Protocol)是生成树协议的英文缩写,可应用于计算机网络中树形拓扑结构建立,主要作用是防止网桥网络中的冗余链路形成环路工作.但某些特定因素会导致STP失败,要排 ...

  6. PHP扩展使用-GD

    一.相关函数 1. 获取信息 gd_info() #查看当前系统环境gd库支持的图片格式 getimagesize(imagefile) #获取图像大小,非GD库函数 imagex(imagefile ...

  7. 深入解读Linux进程调度Schedule【转】

    转自:https://blog.csdn.net/Vince_/article/details/88982802 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文 ...

  8. ubuntu 用户名配置及磁盘挂载

    创建用户 我们创建的这个用户要放到 sudo 用户组,以便于我们可以执行一些需要 root 权限的操作. sudo useradd -m -s /bin/bash username sudo user ...

  9. 阅读高翔的RGBD-SLAM博文笔记

    目录 高翔的RGBD-SLAM笔记 前端VO: 后端优化 高翔的RGBD-SLAM笔记 RGBD相机的特点: 使用RGBD相机中的深度这一维信息,以及相机的针孔成像模型,相机的内参,可以将二维点恢复成 ...

  10. jetbrains 系列编辑器

    下载 webstorm下载地址:https://www.jetbrains.com/webstorm/download/previous.html idea下载地址:https://www.jetbr ...