CompletableFuture实战

一、介绍

CompletableFuture 是 Java 8 中引入的一个接口实现类,它位于 java.util.concurrent 包中。它是一个可以表示异步计算的结果的类,提供了比 Future 更加强大的功能来组合和执行异步操作。CompletableFuture 提供了构建复杂异步计算的能力,而不需要显式地管理线程。

二、依赖引入

CompletableFuture内置于JUC包中,不需要额外引入其他依赖。本文还用到Hutools用于计时器、Lombok用于简化get、set方法和自动生成构造函数

<!--hutool依赖-->
 <dependency>
	<groupId>cn.hutool</groupId>
	<artifactId>hutool-all</artifactId>
	<version>5.8.22</version>
 </dependency>
 <!--junit测试依赖-->
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-test</artifactId>
 </dependency>
 <!--lombok-->
 <dependency>
	  <groupId>org.projectlombok</groupId>
	  <artifactId>lombok</artifactId>
	  <version>1.18.20</version>
 </dependency>

三、前置准备

3.1、实体类

Order

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Order {
    private Long id;
    private Long productId;
    private Long userId;
}

Product

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Product {
    private Long id;
    private String name;
    private Double price;
}

User

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
}

3.2、service层

UserService

import cn.hutool.core.date.DateUtil;
import com.demo.future.entity.User;

import java.util.ArrayList;
import java.util.List;

public class UserService {
    private List<User> list = new ArrayList<>();

    public UserService() {
       list.add(new User(11L,"小明"));
       list.add(new User(22L,"小王"));
       list.add(new User(33L,"张三"));
       list.add(new User(44L,"李四"));
    }

    public List<User> searchUser() {
        System.out.println(DateUtil.now()+"执行UserService的searchUser方法");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return list;
    }
}

OrderService

import cn.hutool.core.date.DateUtil;
import com.demo.future.entity.Order;

import java.util.ArrayList;
import java.util.List;

public class OrderService {
    private List<Order> list = new ArrayList<>();

    public OrderService() {
       list.add(new Order(111L,1L,11L));
       list.add(new Order(222L,2L,22L));
       list.add(new Order(333L,3L,33L));
       list.add(new Order(444L,4L,44L));
    }

    public List<Order> searchOrder() {
        System.out.println(DateUtil.now()+"执行orderService的searchOrder方法");
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return list;
    }
}

ProductService

import cn.hutool.core.date.DateUtil;
import com.demo.future.entity.Product;

import java.util.ArrayList;
import java.util.List;

public class ProductService {
    private List<Product> list = new ArrayList<>();

    public ProductService() {
       list.add(new Product(1L,"苹果",52.4));
       list.add(new Product(2L,"橘子",100.5));
       list.add(new Product(3L,"香蕉",245.1));
       list.add(new Product(4L,"草莓",65.1));
    }

    public List<Product> searchProduct() {
        System.out.println("执行ProductService的searchProduct方法");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return list;
    }
}

四、说明

4.1、传统串行化运行

我们在工作中是不是会经常这样写代码,分别new每个service,然后执行。执行顺序就看哪个方法在前面,就先执行,如果方法陷入阻塞,后续的方法就要等待前面的方法执行完成。这样就是串行化执行,执行顺序是searchUser()->searchProduct()->searchOrder()。

TimeInterval timer = DateUtil.timer();
UserService userService = new UserService();
ProductService productService = new ProductService();
OrderService orderService = new OrderService();
//阻塞了3秒
userService.searchUser();
//阻塞了4秒
productService.searchProduct();
//阻塞了5秒
orderService.searchOrder();
System.out.println("本次执行一共花费" + timer.interval() / 1000 + "秒");

运行这段代码后,输出如下图
在这里插入图片描述

4.2、异步执行所有任务

我们这次用到CompletableFuture.supplyAsync(),这是一个静态方法,用于创建一个 CompletableFuture 实例,它异步执行一个 Supplier 函数,并返回其结果。这个方法通常用于启动一个异步任务,该任务最终会产生一个结果。
方法签名如下:

    /** 简单翻译就是这个方法会返回一个异步完成的新CompletableFuture
     * 他会在共享的commonPool()线程池里面运行
     * Returns a new CompletableFuture that is asynchronously completed
     * by a task running in the {@link ForkJoinPool#commonPool()} with
     * the value obtained by calling the given Supplier.
     *
     * @param supplier a function returning the value to be used
     * to complete the returned CompletableFuture
     * @param <U> the function's return type
     * @return the new CompletableFuture
     */
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
        return asyncSupplyStage(asyncPool, supplier);
    } 
    /** 这个也是一样的,只是多了executor参数,用于执行 supplier 的 Executor
     * Returns a new CompletableFuture that is asynchronously completed
     * by a task running in the given executor with the value obtained
     * by calling the given Supplier.
     *
     * @param supplier a function returning the value to be used
     * to complete the returned CompletableFuture
     * @param executor the executor to use for asynchronous execution
     * @param <U> the function's return type
     * @return the new CompletableFuture
     */
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
                                                       Executor executor) {
        return asyncSupplyStage(screenExecutor(executor), supplier);
    }

我们引入CompletableFuture,来尝试第一种方法,异步执行所有任务。即userService、productService和orderService同时调用方法。

TimeInterval timer = DateUtil.timer();

UserService userService = new UserService();
ProductService productService = new ProductService();
OrderService orderService = new OrderService();

CompletableFuture<List<User>> userFuture = CompletableFuture.supplyAsync(userService::searchUser);
CompletableFuture<List<Product>> productFuture = CompletableFuture.supplyAsync(productService::searchProduct);
CompletableFuture<List<Order>> orderFuture = CompletableFuture.supplyAsync(orderService::searchOrder);
CompletableFuture.allOf(userFuture, productFuture, orderFuture);

System.out.println(userFuture.get());
System.out.println(productFuture.get());
System.out.println(orderFuture.get());

System.out.println("本次执行一共花费" + timer.interval() / 1000 + "秒");

执行结果如下,我们可以看到是同时调用了三个方法,但是由于每个方法阻塞的时间不同,首先是用户信息先返回,然后是产品,最后是订单。因为最大阻塞的时间是5秒,所以执行的时间就是5秒。
在这里插入图片描述

4.3 任务编排

CompletableFuture还有更高级的使用,就是任务编排。顾名思义就是先等A任务执行完成,再去执行BC任务。

执行流程

在这里插入图片描述

方法介绍

    /** 返回一个已完成的新CompletableFuture,相当于直接执行方法
     * Returns a new CompletableFuture that is already completed with
     * the given value.
     *
     * @param value the value
     * @param <U> the type of the value
     * @return the completed CompletableFuture
     */
    public static <U> CompletableFuture<U> completedFuture(U value) {
        return new CompletableFuture<U>((value == null) ? NIL : value);
    }

代码

TimeInterval timer = DateUtil.timer();
UserService userService = new UserService();
ProductService productService = new ProductService();
OrderService orderService = new OrderService();

CompletableFuture<List<User>> userFuture = CompletableFuture.completedFuture(userService.searchUser());
//得到执行结果,执行完成后再继续做下面的操作
System.out.println(userFuture.get());

//异步执行searchProduct()和searchOrder()
CompletableFuture<List<Product>> productFuture = CompletableFuture.supplyAsync(productService::searchProduct);
CompletableFuture<List<Order>> orderFuture = CompletableFuture.supplyAsync(orderService::searchOrder);
CompletableFuture.allOf(productFuture, orderFuture);

System.out.println(productFuture.get());
System.out.println(orderFuture.get());

System.out.println("本次执行一共花费" + timer.interval() / 1000 + "秒");

执行结果

最终执行时间就是A的3秒+C的5秒=8秒
在这里插入图片描述

4.4 任务编排2

我们在实际项目中,会遇到要A和B都是异步执行,但是要等A和B都执行完毕才去执行C,这时候我们就会用到这一种任务编排。

执行流程

在这里插入图片描述

方法介绍

  public <U> CompletableFuture<U> thenApply(
        Function<? super T,? extends U> fn) {
        return uniApplyStage(null, fn);
    }

代码

TimeInterval timer = DateUtil.timer();

UserService userService = new UserService();
ProductService productService = new ProductService();
OrderService orderService = new OrderService();

CompletableFuture<List<User>> userFuture = CompletableFuture.supplyAsync(userService::searchUser);
CompletableFuture<List<Product>> productFuture = CompletableFuture.supplyAsync(productService::searchProduct);

//当productFuture执行完成后,才会运行thenApply里面的函数
CompletableFuture<List<Order>> orderFuture = productFuture.thenApply((products) -> orderService.searchOrder());

CompletableFuture.allOf(userFuture, productFuture);

System.out.println(userFuture.get());
System.out.println(productFuture.get());
System.out.println(orderFuture.get());

System.out.println("本次执行一共花费" + timer.interval() / 1000 + "秒");

执行结果

最终执行时间=searchProduct()的5秒+searchOrder()的四秒
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天吃八顿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值