首页 > 其他分享 >CompletableFuture从入门到精通?算了,入个门就行了

CompletableFuture从入门到精通?算了,入个门就行了

时间:2023-04-07 22:58:40浏览次数:31  
标签:异步 printThreadLog 入门 入个 CommonUtils Future CompletableFuture news

Future vs CompletableFuture

准备工作

为了便于后续更好地调试和学习,我们需要定义一个工具类CommonUtils辅助我们对知识的理解。这个工具类总共四个方法

  • readFile:读取指定路径的文件内容
  • sleepMillis:休眠指定的毫秒数
  • sleepSecond:休眠指定的秒数
  • printThreadLog:打印携带线程信息的日志信息
object CommonUtils {
    fun readFile(pathToFile: String): String {
        return try {
            Files.readString(pathToFile.let { Paths.get(it) })
        } catch (e: Exception) {
            e.printStackTrace()
            ""
        }
    }

    fun sleepMillis(millis: Long) {
        try {
            TimeUnit.MILLISECONDS.sleep(millis)
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
    }

    fun sleepSecond(seconds: Int) {
        try {
            TimeUnit.SECONDS.sleep(seconds.toLong())
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
    }

    fun printThreadLog(message: String?) {
        val result = StringJoiner(" | ")
                .add(System.currentTimeMillis().toString())
                .add(String.format("%2d", Thread.currentThread().id))
                .add(Thread.currentThread().name.toString())
                .add(message)
                .toString()
        println(result)
    }
}

Future 的局限性

需求:替换新闻稿 ( news.txt ) 中敏感词汇 ,把敏感词汇替换成*,敏感词存储在 filter_words.txt 中

news.txt

oh my god!completablefuture真tmd好用

filter_words.txt

尼玛,SB,tmd
fun main(args: Array<String>) {
    val executor = Executors.newFixedThreadPool(5)
    // step1: 读取敏感词汇  thread1
    val filterWordFuture = executor.submit<Array<String>> {
        val str: String = CommonUtils.readFile("filter_words.txt")
        str.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
    }
    // step2: 读取新闻稿 thread2
    val newsFuture: Future<String> = executor.submit<String> { CommonUtils.readFile("news.txt") }

    // step3 : 替换操作 thread3
    val replaceFuture = executor.submit<String> {
        val words = filterWordFuture.get()
        var news = newsFuture.get()
        for (word in words) {
            if (news.indexOf(word) > 0) {
                news = news.replace(word, "**")
            }
        }
        news
    }

    // step 4: 打印输出替换后的新闻稿 main
    val filteredNews = replaceFuture.get()
    println("filteredNews=$filteredNews")
    executor.shutdown()
}

通过上面的代码,我们会发现,Future相比于所有任务都直接在主线程处理,有很多优势,但同时也存在不足,至少表现如下:

  • 在没有阻塞的情况下,无法对Future的结果执行进一步的操作。Future不会告知你它什么时候完成,你如果想要得到结果,必须通过一个get()方法,该方法会阻塞直到结果可用为止。 它不具备将回调函数附加到Future后并在Future的结果可用时自动调用回调的能力。
  • 无法解决任务相互依赖的问题。filterWordFuture和newsFuture的结果不能自动发送给replaceFuture,需要在replaceFuture中手动获取,所以使用Future不能轻而易举地创建异步工作流。
  • 不能将多个Future合并在一起。假设你有多种不同的Future,你想在它们全部并行完成后然后再运行某个函数,Future很难独立完成这一需要。
  • 没有异常处理。Future提供的方法中没有专门的API应对异常处理,还是需要开发者自己手动异常处理。

CompletableFuture 的优势

CompletableFuture 实现了FutureCompletionStage接口

CompletableFuture 相对于 Future 具有以下优势:

  • 为快速创建、链接依赖和组合多个Future提供了大量的便利方法。
  • 提供了适用于各种开发场景的回调函数,它还提供了非常全面的异常处理支持。
  • 无缝衔接和亲和 lambda 表达式 和 Stream - API 。
  • 我见过的真正意义上的异步编程,把异步编程和函数式编程、响应式编程多种高阶编程思维集于一身,设计上更优雅。

创建异步任务

runAsync

如果你要异步运行某些耗时的后台任务,并且不想从任务中返回任何内容,则可以使用CompletableFuture.runAsync()方法。它接受一个Runnable接口的实现类对象,方法返回CompletableFuture<Void> 对象

static CompletableFuture<Void> runAsync(Runnable runnable);

演示案例:开启一个不从任务中返回任何内容的CompletableFuture异步任务

fun main() {
    CommonUtils.printThreadLog("main start")
    // 使用Lambda表达式
    CompletableFuture.runAsync {
        CommonUtils.printThreadLog("读取文件开始");
        // 使用睡眠来模拟一个长时间的工作任务(例如读取文件,网络请求等)
        CommonUtils.sleepSecond(3);
        CommonUtils.printThreadLog("读取文件结束");
    }
    CommonUtils.printThreadLog("here are not blocked,main continue");
    CommonUtils.sleepSecond(4); //  此处休眠为的是等待CompletableFuture背后的线程池执行完成。
    CommonUtils.printThreadLog("main end");
}

supplyAsync

CompletableFuture.runAsync() 开启不带返回结果异步任务。但是,如果您想从后台的异步任务中返回一个结果怎么办?此时,CompletableFuture.supplyAsync()是你最好的选择了。

static CompletableFuture<U>	supplyAsync(Supplier<U> supplier)

它入参一个 Supplier 供给者,用于供给带返回值的异步任务
并返回CompletableFuture<U>,其中U是供给者给程序供给值的类型。

需求:开启异步任务读取 news.txt 文件中的新闻稿,返回文件中内容并在主线程打印输出

fun main() {
    CommonUtils.printThreadLog("main start")

    val newsFuture = CompletableFuture.supplyAsync {

        CommonUtils.readFile("news.txt")
    }
    CommonUtils.printThreadLog("here are not blocked, main continue")
    val news = newsFuture.get()
    CommonUtils.printThreadLog("news=$news")
    CommonUtils.printThreadLog("main end")

}

如果想要获取newsFuture结果,可以调用completableFuture.get()方法,get()方法将阻塞,直到newsFuture完成。

异步任务中的线程池

我们已经知道,runAsync()supplyAsync()方法都是开启单独的线程中执行异步任务。但是,我们从未创建线程对吗? 不是吗!

CompletableFuture 会从全局的`F

标签:异步,printThreadLog,入门,入个,CommonUtils,Future,CompletableFuture,news
From: https://www.cnblogs.com/loveletters/p/completableFutureIntroduction.html

相关文章

  • Spring源码系列一:入门——Hello World
    前言讲解Spring之前,我们首先梳理下Spring有哪些知识点可以进行入手源码分析,比如:SpringIOC依赖注入SpringAOP切面编程SpringBean的声明周期底层原理Spring初始化底层原理SpringTransaction事务底层原理HelloWorld通过这些知识点,后续我们慢慢在深入Spring的使用及原......
  • 第135篇:Three.js基础入门
    好家伙,这东西太帅了,我要学会 先放张帅图(都是用three.js做出来的,这我学习动力直接拉满)  还有另外一个Junniis...帧数太高,录不了 开始学习官方文档1.Three.js是什么?Three.js是一款运行在浏览器中的3D引擎(基于WebGL的API的封装),你可以用它来创造你所需要的......
  • Java入门
    一、Java特性和优势1.简单性:不用像C语言那样引用头文件,抛弃了指针2.面向对象3.可移植性:可以跨平台移植,一次编写多次运行4.高性能:即时编译5.分布式6.动态性:反射机制7.多线程8.安全性9.健壮性二、Java三大版本1.JavaSE:标准版(桌面开发,控制台开发等)2.JavaME:嵌入式开发(......
  • odoo 开发入门教程系列-约束(Constraints)
    约束(Constraints)上一章介绍了向模型中添加一些业务逻辑的能力。我们现在可以将按钮链接到业务代码,但如何防止用户输入错误的数据?例如,在我们的房地产模块中,没有什么可以阻止用户设置负预期价格。odoo提供了两种设置自动验证恒定式的方法:Python约束andSQL约束。SQL参考:与此......
  • 【web 开发基础】PHP 的流程控制之嵌套(巢状)条件分支结构 -PHP 快速入门 (15)
    嵌套条件分支结构嵌套条件分支结构,也称为巢状条件分支结构。其实就是将if语句进行嵌套,即是在if或者else后面的语句块中又包含if语句。if语句可以无限层第嵌套在其他if语句中,这给程序的不同部分的条件执行提供了充分的弹性,是程序设计中经常使用的技术。其语法格式如下所示:if(表达式1......
  • Springfox与SpringDoc——swagger如何选择(SpringDoc入门)
     本文分享自天翼云开发者社区@《Springfox与SpringDoc——swagger如何选择(SpringDoc入门)》,作者:才开始学技术的小白  0.引言之前写过一篇关于swagger(实际上是springfox)的使用指南(https://www.ctyun.cn/developer/article/371704742199365),涵盖了本人在开发与学习的时候碰......
  • Java | 一分钟掌握异步编程 | 5 - CompletableFuture异步
     作者:Mars酱 声明:本文章由Mars酱编写,部分内容来源于网络,如有疑问请联系本人。 转载:欢迎转载,转载前先请联系我!前言继续讲,前面讲了Future实现异步,优点缺点也都有,这里讲使用CompletableFuture机制,目前为止,应该说JDK原生提供的异步方式的最优方案就是CompletableFuture了,已知的开源......
  • RabbitMQ入门(Windows)
    一、MQ概述MQ全称MessageQueue(消息队列),在消息队列中,通常有生产者和消费者两个角色。生产者只负责发送数据到消息队列,谁从消息队列中取出数据处理,他不管。消费者只负责从消息队列中取出数据处理,他不管这是谁发送的数据MQ,消息队列,存储消息的中间件分布式系统通信两种方式:直接......
  • SpringBoot2核心技术篇(自动配置原理入门[二])
    自动配置原理入门3.1引导加载自动配置类@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters={@Filter(type=FilterType.CUSTOM,classes={TypeExcludeFilter.class}),@Filter(type=FilterType.CUSTOM,classes=......
  • JUC并发编程基础篇第二章之CompletableFuture[加强版的线程]
    @目录1、创建线程的几种方式2、Future的优缺点3、CompletableFuture对Future的改进3.1、CompletableFuture的基本结构3.2、创建CompletableFuture四种方式3.3、CompletableFuture的流式调用3.4、CompletableFuture常见的用法1、创建线程的几种方式newthread://构造......