CompletableFuture是Java8提供的一个并发类,方法很多,使用相对复杂。

使用场景:多个线程需要并行或者串行等发杂场景。

先示例一下CompletableFuture的简单场景,上一篇中讲到一个场景是,A和B并行执行,其中结果给C再去执行。

使用CompletableFuture会更简便易于理解。


CompletableFutureDemo.java


package com.example.demo.concurrent.completablefuture;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Slf4j
public class CompletableFutureDemo {
    public static void main(String[] args) {
        //如果是runAsync方法,则不需要return
        CompletableFuture completableFuture = CompletableFuture.supplyAsync(()->{
            log.info("执行线程-----开始----");
            try {
                TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                log.info("执行线程-----处理数据中----无操作--无返回--");
                log.info("执行线程-----结束----");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return new Result("飞翔的咩咩","1");
        });
        //需要返回结果
        CompletableFuture completableFutureA = CompletableFuture.supplyAsync(()->{
            log.info("执行线程A-----开始----");
            try {
                TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                log.info("执行线程A-----处理数据中-----");
                log.info("执行线程A-----结束----");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return new Result("飞翔的咩咩A","25");
        });
        //需要返回结果
        CompletableFuture completableFutureB = CompletableFuture.supplyAsync(()->{
            log.info("执行线程B-----开始----");
            try {
                TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                log.info("执行线程B-----数据处理中:----");
                log.info("执行线程B-----结束----");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return new Result("飞翔的咩咩B","25");
        });
        //C会等待A和B结束后执行。
        CompletableFuture completableFutureC = completableFutureA.thenCombine(completableFutureB,(resultA,resultB)->{
            log.info("执行线程保存处理结果-----开始----");
            List<Result> resultList = new ArrayList<Result>();
            Result rsA = (Result) resultA;
            Result rsB = (Result) resultB;
            try {
                TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                rsA.setAge(String.valueOf(Integer.parseInt(rsA.getAge())+1));
                rsB.setAge(String.valueOf(Integer.parseInt(rsB.getAge())+1));
                log.info("执行线程保存处理结果-----resultA,age+1后为:{}----",rsA.toString());
                log.info("执行线程保存处理结果-----resultB,age+1后为:{}----",rsB.toString());
                resultList.add(rsA);
                resultList.add(rsB);
                log.info("执行线程保存处理结果-----结束----");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return resultList;
        });

        System.out.println(completableFutureC.join());


    }
}

执行结果为:这个逻辑是,A和B异步执行,C等待他们的结果,并且都在age上加1.再输出

00:03:25.836 [ForkJoinPool.commonPool-worker-11] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程B-----开始----
00:03:25.836 [ForkJoinPool.commonPool-worker-9] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程-----开始----
00:03:25.836 [ForkJoinPool.commonPool-worker-2] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程A-----开始----
00:03:25.838 [ForkJoinPool.commonPool-worker-2] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程A-----处理数据中-----
00:03:25.838 [ForkJoinPool.commonPool-worker-2] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程A-----结束----
00:03:26.848 [ForkJoinPool.commonPool-worker-11] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程B-----数据处理中:----
00:03:26.848 [ForkJoinPool.commonPool-worker-11] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程B-----结束----
00:03:26.848 [ForkJoinPool.commonPool-worker-11] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程保存处理结果-----开始----
00:03:27.848 [ForkJoinPool.commonPool-worker-9] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程-----处理数据中----无操作--无返回--
00:03:27.848 [ForkJoinPool.commonPool-worker-9] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程-----结束----
00:03:27.868 [ForkJoinPool.commonPool-worker-11] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程保存处理结果-----resultA,age+1后为:Result{name='飞翔的咩咩A', age='26'}----
00:03:27.868 [ForkJoinPool.commonPool-worker-11] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程保存处理结果-----resultB,age+1后为:Result{name='飞翔的咩咩B', age='26'}----
00:03:27.868 [ForkJoinPool.commonPool-worker-11] INFO com.example.demo.concurrent.completablefuture.CompletableFutureDemo1 - 执行线程保存处理结果-----结束----
[Result{name='飞翔的咩咩A', age='26'}, Result{name='飞翔的咩咩B', age='26'}]

CompletableFuture功能很强大,实现了Future<T>和 CompletionStage<T>,实现Future<T>能获取异步结果。实现CompletionStage<T>能使用很多强大功能。

在这里我们仅使用两个方法:


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


CompletableFuture<V> thenCombine( CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)


其中supplyAsync(Supplier<U> supplier)是有返回的,不需要返回可以用

CompletableFuture<Void> runAsync(Runnable runnable)

我们看一下runAsync源码

/**
     * Returns a new CompletableFuture that is asynchronously completed
     * by a task running in the {@link ForkJoinPool#commonPool()} after
     * it runs the given action.
     *
     * @param runnable the action to run before completing the
     * returned CompletableFuture
     * @return the new CompletableFuture
     */
    public static CompletableFuture<Void> runAsync(Runnable runnable) {
        return asyncRunStage(asyncPool, runnable);
    }


因为没有传线程池就使用了默认的ForkJoinPool.commonPool(),默认是创建CPU核数的线程池大小,有耗时任务时可能造成线程不够。建议自定义线程池,避免互相干扰。