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. Entity Framework 导航属性(2)

    1.学校 [Table("School")] public partial class School { public School() { Students = new List ...

  2. Lambda(一)lambda表达式初体验

    Lambda(一)lambda表达式初体验 Lambda引入 : 随着需求的不断改变,代码也需要随之变化 需求一:有一个农场主要从一堆苹果中挑选出绿色的苹果 解决方案:常规做法,source code ...

  3. jQuery-ready与load

      // ready 在DOM加载完成时运行的代码 $(document).ready(function(){ // 在这里写代码... }) // 可以简写为 $(function(){ // 在这 ...

  4. iOS开发之--隐藏状态栏

    1,全局隐藏 在Targets->General->勾选中Hide status bar .,如下图: 2.单个页面隐藏/展示状态栏 1).首先在info.plist里面View cont ...

  5. 我的第一次diy装机记录——小白的装机篇

    接上一篇<我的第一次diy装机记录——小白的配置篇> 处理器 AMD Ryzen 5 2600X 六核主板 微星 B450M MORTAR (MS-7B89) ( AMD PCI 标准主机 ...

  6. Windows下硬盘存储情况可视化工具--WinDirStat

    WinDirStat是一款免费的用于Windows下硬盘空间可视化工具. 下载地址:https://windirstat.en.softonic.com/ 界面如图所示: 可以轻易看出硬盘空间使用情况 ...

  7. JDBC学习笔记二

    JDBC学习笔记二 4.execute()方法执行SQL语句 execute几乎可以执行任何SQL语句,当execute执行过SQL语句之后会返回一个布尔类型的值,代表是否返回了ResultSet对象 ...

  8. 5.2 RDD编程---键值对RDD

    一.键值对RDD的创建 1.从文件中加载 2.通过并行集合(数组)创建RDD 二.常用的键值对RDD转换操作 1.reduceByKey(func) 功能:使用func函数合并具有相同键的值 2.gr ...

  9. css 文本属性和字体属性

    1.将浮动居中 这需要三个盒子 <!DOCTYPE html> <html lang="en"> <head> <meta charset ...

  10. 283.移动零 关于列表list与remove原理*****(简单)

    题目: 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 注意,该题目要求不开辟行的数组空间,在原数据上进行操作. 示例: 输入: [0,1,0,3,12 ...