前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >01-CompletableFuture异步线程 入门

01-CompletableFuture异步线程 入门

作者头像
彼岸舞
发布2022-05-10 11:14:08
2050
发布2022-05-10 11:14:08
举报
文章被收录于专栏:java开发的那点事

前言

emmm, 有好长一段时间没有发布新的文章了,最后一篇发布还是1月21日,到现在已经快3个月了,这段时间我去干嘛了呢?

1: 学习数据结构与算法, 但是还没有学完,打算等学习完毕后再给大家分享

2: 学习Java 9 - 15的新特性, 应为关注Java的发展方向这一块来说,基本是每个学习Java的人员所必备的, 为啥没有16和17呢?应为我在网上没有找到好的视频,所以等以后找到了在学习而且新特特性应该不是很多,但是9-17加起来就很多了

3: 就是最近这段时间我离职了, 在交接和找新的工作,所很大一部分精力都用在了这个上面

但是今天给大家带来了一个新的东西,这个东西用的人也比较少, 其实也不是很新,是Java8中的一个类而已,但是非常好用, 用过多线程的人应该都知道,线程的创建,回收,管理,池化,都很难弄, 但是学习了这个东西, 妈妈再也不用担心我用不好多线程了

CompletableFuture是什么

从名称看来和Future有关,没错,他也是Future的实现,和FutureTask平级,也是用来实现异步线程任务的,并且携带返回值, 具体的使用直接从需求出发,关注下面的需求和实现, 即可掌握

需求

小白来餐厅吃饭, 点了一盘番茄炒蛋+米饭,小白开始打王者,厨师开始炒菜,小白开吃

需求点: 厨师需要单独的线程

实现

编写代码

代码语言:javascript
复制
package com.dance;

import org.junit.jupiter.api.Test;

import java.util.StringJoiner;
import java.util.concurrent.CompletableFuture;

public class CompletableFutureTest {

    @Test
    public void testOne(){
        print("小白进入餐厅");
        print("小白点了 番茄炒蛋 + 一碗米饭");
        CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
            print("厨师炒菜");
            sleep(200);
            print("厨师打饭");
            sleep(100);
            return "番茄炒蛋 + 米饭 好了";
        });
        print("小白在打王者");
        print(String.format("%s , 小白开吃", cf1.join()));
    }

    /**
     * 休眠方法
     * @param millis 毫秒
     */
    public static void sleep(long millis){
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 打印方法
     * @param text 文本
     */
    public static void print(String text){
        String str = new StringJoiner("\t|\t")
                .add(String.valueOf(System.currentTimeMillis()))
                .add(String.valueOf(Thread.currentThread().getId()))
                .add(Thread.currentThread().getName())
                .add(text)
                .toString();
        System.out.println(str);
    }

}

执行结果

代码语言:javascript
复制
1649430128924    |    1    |    main    |    小白进入餐厅
1649430128924    |    1    |    main    |    小白点了 番茄炒蛋 + 一碗米饭
1649430128926    |    1    |    main    |    小白在打王者
1649430128927    |    24    |    ForkJoinPool.commonPool-worker-19    |    厨师炒菜
1649430129134    |    24    |    ForkJoinPool.commonPool-worker-19    |    厨师打饭
1649430129244    |    1    |    main    |    番茄炒蛋 + 米饭 好了 , 小白开吃

厨师用单独的线程去干活了, 异步线程,如此简单

需求进化

在餐厅中一般厨师都只负责炒菜,像打饭这样的事情都是交给服务员来的

需求点:厨师炒完菜后交给服务员,服务员新开线程去打饭

实现

编写代码

代码语言:javascript
复制
@Test
public void testTwo(){
    print("小白进入餐厅");
    print("小白点了 番茄炒蛋 + 一碗米饭");
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        print("厨师炒菜");
        sleep(200);
        return "番茄炒蛋";
    }).thenCompose(dis -> CompletableFuture.supplyAsync(() -> {
        print("服务员打饭");
        sleep(100);
        return dis + " + 米饭 好了";
    }));
    print("小白在打王者");
    print(String.format("%s , 小白开吃", cf1.join()));
}

执行结果

代码语言:javascript
复制
1649431094323    |    1    |    main    |    小白进入餐厅
1649431094324    |    1    |    main    |    小白点了 番茄炒蛋 + 一碗米饭
1649431094326    |    1    |    main    |    小白在打王者
1649431094326    |    24    |    ForkJoinPool.commonPool-worker-19    |    厨师炒菜
1649431094538    |    24    |    ForkJoinPool.commonPool-worker-19    |    服务员打饭
1649431094645    |    1    |    main    |    番茄炒蛋 + 米饭 好了 , 小白开吃

按道理来说这里应该是两个线程的,但是估计我这个执行的太快了,所以后面的任务也提交给了这个线程,我感觉这种代码调用流程就很清晰,看着像Promise

需求进化

小白进入餐厅的时候,开始点菜,要一盘番茄炒蛋+米饭, 但是这个时候米饭是没有蒸好的,需要开始去蒸,所以厨师炒菜,服务员去蒸饭,这两个事情应该是同时进行的,在厨师炒完菜,服务员蒸好饭,厨师将菜交给服务员,服务员打饭,交给小白,小白吃饭

需求点: 厨师炒菜和服务员蒸饭需要同时进行,并且是厨师炒完菜交给服务员

实现

编写代码

代码语言:javascript
复制
@Test
public void testThree(){
    print("小白进入餐厅");
    print("小白点了 番茄炒蛋 + 一碗米饭");
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        print("厨师炒菜");
        sleep(200);
        return "番茄炒蛋";
    }).thenCombine(CompletableFuture.supplyAsync(() -> {
        print("服务员开始蒸饭");
        sleep(300);
        return "米饭";
    }), (dis, rice) -> {
        print("服务员打饭");
        sleep(100);
        return String.format("%s + %s , 好了", dis, rice);
    });
    print("小白在打王者");
    print(String.format("%s , 小白开吃", cf1.join()));
}

执行结果

代码语言:javascript
复制
1649431885256    |    1    |    main    |    小白进入餐厅
1649431885256    |    1    |    main    |    小白点了 番茄炒蛋 + 一碗米饭
1649431885259    |    1    |    main    |    小白在打王者
1649431885259    |    24    |    ForkJoinPool.commonPool-worker-19    |    服务员开始蒸饭
1649431885259    |    25    |    ForkJoinPool.commonPool-worker-5    |    厨师炒菜
1649431885571    |    24    |    ForkJoinPool.commonPool-worker-19    |    服务员打饭
1649431885681    |    1    |    main    |    番茄炒蛋 + 米饭 , 好了 , 小白开吃

这里出现了两个线程,正好可以看到

总结

方法名

描述

supplyAsync

用来开启一个异步任务

thenCompose

用来连接两个有依赖关系的任务,结果由最后一个返回

thenCombine

用来合并两个任务,结果由函数(BiFunction)返回

第一个任务的需求点在于线程的开启

第二个任务的需求点在于两个线程的连接

第三个任务的需求点在于两个线程的结果合并

怎么样到这里是不是已经简单的入门了呢

作者:彼岸舞

时间:2022\04\11

内容关于:CompeletableFuture

本文来源于网络,只做技术分享,一概不负任何责任

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • CompletableFuture是什么
  • 需求
  • 实现
    • 编写代码
      • 执行结果
      • 需求进化
      • 实现
        • 编写代码
          • 执行结果
          • 需求进化
          • 实现
            • 编写代码
              • 执行结果
              • 总结
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档