CompletableFuture.allOf()--并行多任务同步返回之大宝剑

2,380 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

前言

在有些时候我们会碰见处理多个任务, 而几个任务之间又没有联系的情况, 这个时候使用串行处理就会非常的慢, 我们可以使用并行处理这多个任务并最终同步返回给客户端, 从而加快接口的返回速度

CompletableFuture

image.png

我们可以看到这是since 1.8的类, 即jdk1.8出的新的java util, 在juc包下. 具体其他用法不谈只看一下allOf方法.

用法

package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

@RestController
public class FutureController {

    @GetMapping("hello")
    public String hello() {
        long start = System.currentTimeMillis();
        sleep();
        sleep();
        sleep();
        long end = System.currentTimeMillis();
        return "hello(): 耗时" + (end - start) + "ms";
    }

    /**
     * 模拟一个耗时的操作
     */
    private void sleep() {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("休眠结束!");
    }
}

测试一下

可以看到模拟的耗时操作串行, 导致三秒返回结果

image.png

使用CompletableFuture.allOf()

package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

@RestController
public class FutureController {

    @GetMapping("hello")
    public String hello() {
        long start = System.currentTimeMillis();
        sleep();
        sleep();
        sleep();
        long end = System.currentTimeMillis();
        return "hello(): 耗时" + (end - start) + "ms";
    }

    @GetMapping("future")
    public String future() {
        long start = System.currentTimeMillis();
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(
                CompletableFuture.runAsync(this::sleep),
                CompletableFuture.runAsync(this::sleep),
                CompletableFuture.runAsync(this::sleep)
        );
        try {
            voidCompletableFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        return "future(): 耗时" + (end - start) + "ms";
    }

    /**
     * 模拟一个耗时的操作
     */
    private void sleep() {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("休眠结束!");
    }
}

测试Future

可以看到返回变快

image.png

后记

这就是CompletableFuture.allOf()的用法了 如果是对数据库的操作, 建议优化点要放在数据库语句或索引的优化, 使用这种方式会加大数据库的压力, 尤其是并发量高的接口应该慎用.