首页 > 编程语言 >JUC 异步编程利器 CompletableFuture 介绍

JUC 异步编程利器 CompletableFuture 介绍

时间:2024-01-14 12:56:46浏览次数:28  
标签:JUC 异步 get FutureTask 任务 Future CompletableFuture futureTask

1 从FutureTask到CompletableFuture

1.1 Future

Future接口(FutureTask实现类)定义了操作异步任务执行一些方法,如获取异步任务的执行结果、取消异步任务的执行、判断任务是否被取消、判断任务执行是否完毕等。
举例:比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务后,主线程就去做其他事情了,忙完其他事情或者先执行完,过了一会再才去获取子任务的执行结果或变更的任务状态(老师上课时间想喝水,他继续讲课不结束上课这个主线程,让学生去小卖部帮老师买水完成这个耗时和费力的任务)。

1.2 Future接口常用实现类FutureTask异步任务

1.2.1 Future接口能干什么

Future是Java5新加的一个接口,它提供一种异步并行计算的功能,如果主线程需要执行一个很耗时的计算任务,我们会就可以通过Future把这个任务放进异步线程中执行,主线程继续处理其他任务或者先行结束,再通过Future获取计算结果。

1.2.2 Future接口相关架构

UML图

public class CompletableFutureDemo {

    @SneakyThrows
    public static void main(String[] args) {

        FutureTask<String> futureTask = new FutureTask<>(new MyThread());

        Thread thread = new Thread(futureTask);
        thread.start();

        System.out.println(futureTask.get());

    }

}

class MyThread implements Callable<String >{

    @Override
    public String call() throws Exception {

        System.out.println("----come in call()");

        return "hello Callable";
    }
}

1.2.3 Future编码实战和优缺点分析

● 优点:Future+线程池异步多线程任务配合,能显著提高程序的运行效率。
● 缺点:
○ get()阻塞---一旦调用get()方法求结果,一旦调用不见不散,非要等到结果才会离开,不管你是否计算完成,如果没有计算完成容易程序堵塞。
○ isDone()轮询---轮询的方式会耗费无谓的cpu资源,而且也不见得能及时得到计算结果,如果想要异步获取结果,通常会以轮询的方式去获取结果,尽量不要阻塞。
● 结论:Future对于结果的获取不是很友好,只能通过阻塞或轮询的方式得到任务的结果。

1.2.3.1 get()阻塞演示
package com.kwfruit.thread.step01;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

@Slf4j
public class FutureAPIDemo {
    
    @SneakyThrows
    public static void main(String[] args) {
        
        FutureTask<String> futureTask = new FutureTask<>(()->{
            log.debug("[{}] ------come in",Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(3);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            return "task over";
        });
        
        Thread t1   = new Thread(futureTask);
        t1.start();
         /**
         * 获取异步任务返回的结果值
         * 必须拿到返回结果才能往下执行
         */
        log.debug("futureTask 结果值:{}",futureTask.get());
        

      //System.out.println(futureTask.get(3,TimeUnit.SECONDS));
        System.out.println("嘻嘻嘻");
    }
    
    
}

结论:一旦调用get()方法求结果,一旦调用不见不散,非要等到结果才会离开,不管你是否计算完成,如果没有计算完成容易程序堵塞

1.2.3.2 isDone()轮询

上面介绍了 用FutureTask get()方法获取返回值 会造成程序阻塞,如果线程没有执行完,没有返回结果,会一直等待下去。下面我们用isDone()方法配合get()方法进行优化,用打印日志的方式监控程序的执行状态。

package com.kwfruit.thread.step01;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

@Slf4j
public class FutureAPIDemo {
    
    @SneakyThrows
    public static void main(String[] args) {
        
        FutureTask<String> futureTask = new FutureTask<>(()->{
            log.debug("[{}] ------come in",Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(3);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            return "task over";
        });
        
        Thread t1   = new Thread(futureTask);
        t1.start();


        while (true){
           if (futureTask.isDone()){
               log.error("futureTask 的值为:[{}]",futureTask.get());
              break;
           }else{
               try {
                   TimeUnit.MILLISECONDS.sleep(300);
               }catch (InterruptedException e){
                   e.printStackTrace();
               }
               log.error("等待程序执行中......");
           }
       }
    }  
}


结论:轮询的方式会耗费无谓的cpu资源,而且也不见得能及时得到计算结果,如果想要异步获取结果,通常会以轮询的方式去获取结果,尽量不要阻塞

1.3 总结

● 对于简单的业务场景使用Future完全ok
● 回调通知:
○ 应对Future的完成时间,完成了可以告诉我,也就是我们的回调通知
○ 通过轮询的方式去判断任务是否完成这样非常占cpu并且代码也不优雅
● 创建异步任务:Future+线程池组合
● 多个任务前后依赖可以组合处理(水煮鱼--->买鱼--->调料--->下锅):
○ 想将多个异步任务的结果组合起来,后一个异步任务的计算结果需要钱一个异步任务的值
○ 想将两个或多个异步计算合并成为一个异步计算,这几个异步计算互相独立,同时后面这个又依赖前一个处理的结果
● 对计算速度选最快的:
○ 当Future集合中某个任务最快结束时,返回结果,返回第一名处理结果
● 结论:
○ 使用Future之前提供的那点API就囊中羞涩,处理起来不够优雅,这时候还是让CompletableFuture以声明式的方式优雅的处理这些需求。
○ 从i到i++
○ Future能干的,CompletableFuture都能干

标签:JUC,异步,get,FutureTask,任务,Future,CompletableFuture,futureTask
From: https://www.cnblogs.com/mangoubiubiu/p/17963555

相关文章

  • 用这4招 优雅的实现Spring Boot 异步线程间数据传递
    你好,我是蜗牛!在实际开发中需要在父子线程之间传递一些数据,比如用户登录信息使用ThreadLocal存放保证线程隔离,代码如下:/***@author公众号:woniuxgg*@description用户上下文信息*/publicclassUserUtils{privatestaticfinalThreadLocal<String>userLocal=new......
  • vue 高德地图异步引用
    先建立一个文件,引入高德  gDMapLoader.jsconstak='4e9f15de14b05fd8f19e1d8fbe91f0a3'exportdefaultfunctionload(){returnnewPromise(function(resolve,reject){if(window.AMap){resolve(window.AMap)}else{varscript=doc......
  • SpringBoot中使用SpringEvent业务解耦神器实现监听发布事件同步异步执行任务
    场景SpringBoot中使用单例模式+ScheduledExecutorService实现异步多线程任务(若依源码学习):https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/135504554设计模式-观察者模式在Java中的使用示例-环境监测系统:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/det......
  • 优雅处理并发:Java CompletableFuture最佳实践
    第1章:引言大家好,我是小黑,今天,小黑要和大家聊聊CompletableFuture,这个Java8引入的强大工具。在Java传统的Future模式里,咱们都知道,一旦开始了一个异步操作,就只能等它结束,无法知道执行情况,也不能手动完成或者取消。而CompletableFuture呢,就像它的名字一样,是可以"完全控制"的Futur......
  • SpringBoot中使用单例模式+ScheduledExecutorService实现异步多线程任务(若依源码学习
    场景若依前后端分离版手把手教你本地搭建环境并运行项目:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108465662设计模式-单例模式-饿汉式单例模式、懒汉式单例模式、静态内部类在Java中的使用示例:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/......
  • 使用CompletableFuture提升代码执行效率示例
    代码示例/***全国/区域数据统计:*1.新能源规模*2.电网容量*3.输配线路*4.变电站*5.工作场站**@paramareaarea*@paramuseruser*@returntheobject*@since3.0.0*/publicSt......
  • 记一次JSF异步调用引起的接口可用率降低
    前言本文记录了由于JSF异步调用超时引起的接口可用率降低问题的排查过程,主要介绍了排查思路和JSF异步调用的流程,希望可以帮助大家了解JSF的异步调用原理以及提供一些问题排查思路。本文分析的JSF源码是基于JSF1,7.5-HOTFIX-T6版本。起因问题背景1.广告投放系统是典型的I/O密集型(I/......
  • 使用C#编写异步爬虫程序:爬取美图录网站精美图片内容并下载到本地
    使用C#编写的爬虫程序,用于爬取美图录网站上的图片内容。使用了HttpClient和Json.Net库。usingSystem;usingSystem.Net.Http;usingSystem.Threading.Tasks;usingNewtonsoft.Json.Linq;http://www.jshk.com.cn/mb/reg.asp?kefu=xiaoding;//爬虫IP免费获取;classProgram{......
  • 批量爬取百度图片(异步+网络请求解析)
     4、分析百度图片搜索返回结果的HTML代码,或找一图片网站,编写爬虫抓取图片并下载形成专题图片。#########分析#########  #使用网络工具查看百度图片的组成,我们可以发现他的分类中的模块是  #通过一个a标签包揽的,这就表明,我们可以设置两层循环(由于此时下载的东西会......
  • python爬虫进阶篇(异步)
    学习完前面的基础知识后,我们会发现这些爬虫的效率实在是太低了。那么我们需要学习一些新的爬虫方式来进行信息的获取。异步        使用python3.7后的版本中的异步进行爬取,多线程虽然快,但是异步才是爬虫真爱。基本概念讲解1.什么是异步?        异步是指在程序执行......