User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   Java   ›   正文
Java

Java—Future与FutureTask的区别与联系

2020-10-25 18:49:30
1576  0 1
参考目录 隐藏
1) Future模式简述
2) Future
3) FutureTask
4) 举个栗子
5) 直接使用Futrue来接收返回值:(结合callable)
6) FutureTask获取结果:(结合Callbale使用)
7) 总结

阅读完需:约 7 分钟

Future模式简述

  • 传统单线程环境下,调用函数是同步的,必须等待程序返回结果后,才可进行其他处理。 Futrue模式下,调用方式改为异步。
  • Futrue模式的核心在于:充分利用主函数中的等待时间,利用等待时间处理其他任务,充分利用计算机资源。

所谓异步调用其实就是实现一个可无需等待被调用函数的返回值而让操作继续运行的方法。在 Java 语言中,简单的讲就是另启一个线程来完成调用中的部分计算,使调用继续运行或返回,而不需要等待计算结果。但调用者仍需要取线程的计算结果。

JDK5新增了Future接口,用于描述一个异步计算的结果。虽然 Future 以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的初衷相违背,轮询的方式又会耗费无谓的 CPU 资源,而且也不能及时地得到计算结果。

Future

Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果等操作。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
Future类位于java.util.concurrent包下,它是一个接口:

public interface Future<V> {
    /**
     * 方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。
     *
     * @param mayInterruptIfRunning 表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。
     * @return 如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;
     * 如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;
     * 如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
     * 方法表示任务是否被取消成功
     * @return 如果在任务正常完成前被取消成功,则返回 true
     */
    boolean isCancelled();

    /**
     * 方法表示任务是否已经完成
     * @return 若任务完成,则返回true
     */
    boolean isDone();

    /**
     * 方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回
     * @return 任务执行的结果值
     * @throws InterruptedException
     * @throws ExecutionException
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * 用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null(并不是抛出异常,需要注意)。
     * @param timeout 超时时间
     * @param unit 超时单位
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     * @throws TimeoutException
     */
    V get(long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException;
}

从上面方法的注释可以看出,Futrue提供了三种功能:

  1. 判断任务是否完成;
  2. 够中断任务;
  3. 能够获取任务执行结果。(最为常用的)

因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask(JDK8以前唯一实现类)。

Java—Future模式(设计思想)

FutureTask

public class FutureTask<V> implements RunnableFuture<V>
      public interface RunnableFuture<V> extends Runnable, Future<V>

由此看出FutureTask它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

FutureTask提供了2个构造器:

// 包装callable
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}

//把Runable转换成callable来处理(结果尽然让传进来,所以这个方法没啥用)
public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}
  • FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。
  • FutureTask实现了Futrue可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。

举个栗子

直接使用Futrue来接收返回值:(结合callable)
    public static void main(String args[]) {
        Instant start = Instant.now();

        ExecutorService executor = Executors.newCachedThreadPool();
        //执行callable任务  拿到但绘制result
        Future<Integer> result = executor.submit(() -> {
            System.out.println("子线程在进行计算");
            Thread.sleep(3000);
            int sum = 0;
            for (int i = 0; i < 100; i++)
                sum += i;
            return sum;
        });
        Instant mid = Instant.now();
        System.out.println("Mid拿到Futrue结果对象result:" + Duration.between(start, mid).toMillis());

        try {
            System.out.println("task运行结果计算的总和为:" + result.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        executor.shutdown();

        Instant end = Instant.now();
        System.out.println("End拿到结果值:" + Duration.between(start, end).toMillis());
    }
输出:
子线程在进行计算
Mid拿到Futrue结果对象result:98
task运行结果计算的总和为:4950
End拿到结果值:3099

我们很显然可以发现,mid的时间很短,主线程马上向下执行了,但是end的时间就比较长了,因此get()拿结果属于阻塞方法。

FutureTask获取结果:(结合Callbale使用)
    public static void main(String args[]) {
        Instant start = Instant.now();

        ExecutorService executor = Executors.newCachedThreadPool();
        //使用FutureTask包装callbale任务,再交给线程池执行
        FutureTask<Integer> futureTask = new FutureTask<>(() -> {
            System.out.println("子线程在进行计算");
            Thread.sleep(3000);
            int sum = 0;
            for (int i = 0; i < 100; i++)
                sum += i;
            return sum;
        });
        //线程池执行任务 这个返回值不需要了,直接就在futureTask对象里面了
        executor.submit(futureTask);

        Instant mid = Instant.now();
        System.out.println("Mid拿到futureTask结果对象result:" + Duration.between(start, mid).toMillis());

        try {
            System.out.println("task运行结果计算的总和为:" + futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        executor.shutdown();

        Instant end = Instant.now();
        System.out.println("End拿到结果值:" + Duration.between(start, end).toMillis());
    }
输出:
子线程在进行计算
Mid拿到futureTask结果对象result:86
task运行结果计算的总和为:4950
End拿到结果值:3088

第二种方式(只是进行了简单包装而已):

//第二种方式,注意这种方式和第一种方式效果是类似的,只不过一个使用的是ExecutorService,一个使用的是Thread
        FutureTask<Integer> futureTask = new FutureTask<>(() -> {
            System.out.println("子线程在进行计算");
            Thread.sleep(3000);
            int sum = 0;
            for (int i = 0; i < 100; i++)
                sum += i;
            return sum;
        });
        Thread thread = new Thread(futureTask);
        thread.start();

如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。

Callable和Futrue的区别:Callable用于产生结果,Future用于获取结果

总结

Futrue的使用和FutrueTask的使用,没有本质的区别。

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

1 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 593860浏览

随机文章
Java— I/O流框架
4年前
SpringMVC—Ajax结合
5年前
SpringBoot—路径映射
5年前
整合SSM框架
5年前
Spring笔记14—整合MyBatis
5年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 593860 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付