多线程——CompletableFuture异步编排

本文详细介绍了Java的CompletableFuture类,包括如何创建异步任务、处理结果、异常捕获和多任务组合。通过实例展示了runAsync、supplyAsync、whenComplete、exceptionally、handle、thenApply、thenAccept、thenRun等方法的使用,以及如何进行线程串行化和多任务组合。文章深入浅出地阐述了CompletableFuture在并发编程中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 创建异步对象

CompletableFuture提供了4个静态的方法来创建一个异步操作

1.1 没有返回值

1)public static CompletableFuture<Void> runAsync(Runnable runnable)

2)public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor)

例如:

public class CompletableFutureTest {

    // 创建一个10个线程的线程池  注意:一个系统应该只有有限的线程池,每个异步任务,都交给线程池,让其去执行
    public static ExecutorService service = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main。。。");

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("线程" + Thread.currentThread().getId() + "运行结果:" + i);
        }, service);

        Void aVoid = future.get();
        System.out.println(aVoid);

        System.out.println("main。。。end");
    }
}

 执行结果:

通过执行结果,可以知道runXXX虽然是不带返回值的,其实我们也可以通过future.get()来获取到一个Void对象,其值为null,同时,get方法是阻塞的方法,所以main.end最后执行,因此,也可以使用get()方法来做线程控制。

1.2 带返回值

1)public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
2)public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor)

注意:参数executor表示线程池,如果不传,那么使用默认的线程池

例如:

public class CompletableFutureTest {

    // 创建一个10个线程的线程池  注意:一个系统应该只有有限的线程池,每个异步任务,都交给线程池,让其去执行
    public static ExecutorService service = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main。。。");

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("线程" + Thread.currentThread().getId() + "运行结果:" + i);
            return i;
        }, service);
        Integer i = future.get();
        System.out.println("i = " + i);

        System.out.println("main。。。end");
    }
}

执行结果:

2. 方法完成时的感知whenComplete

CompletableFuture提供了类似JS中Promise的功能,可以让指定的任务执行完毕之后,回调某个函数,CompletableFuture也提供了四个回调函数

public CompletableFuture<T> whenComplete(
        BiConsumer<? super T, ? super Throwable> action) {
    return uniWhenCompleteStage(null, action);
}

public CompletableFuture<T> whenCompleteAsync(
        BiConsumer<? super T, ? super Throwable> action) {
    return uniWhenCompleteStage(asyncPool, action);
}

public CompletableFuture<T> whenCompleteAsync(
        BiConsumer<? super T, ? super Throwable> action, Executor executor) {
    return uniWhenCompleteStage(screenExecutor(executor), action);
}

public CompletableFuture<T> exceptionally(
        Function<Throwable, ? extends T> fn) {
    return uniExceptionallyStage(fn);
}

whenComplete和whenCompleteAsync可以处理正常和异常的计算结果,exceptionslly处理异常情况。

2.1 whenComplete与whenCompleteAsybc的区别

1)whenComplete:是执行当前任务的线程执行继续执行whenComplete的任务

public static void main(String[] args) throws ExecutionException, InterruptedException {
    System.out.println("main。。。");

    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("当前线程:" + Thread.currentThread().getId());
        int i = 10 / 2;
        System.out.println("线程" + Thread.currentThread().getId() + "运行结果:" + i);
        return i;
    }, service).whenComplete((res,exception) -> {
        System.out.printf("执行的结果是%d,异常信息是%s\r\n",res,exception);
    });

    System.out.println("main。。。end");
    service.shutdown();

}

执行结果:

如果有异常

public static void main(String[] args) throws ExecutionException, InterruptedException {
    System.out.println("main。。。");

    CompletableFuture<Integer> future =
            CompletableFuture.supplyAsync(() -> 10/0, service)
                    .whenComplete((res,exception) -> {
                        System.out.printf("执行的结果是%d,异常信息是%s\r\n",res,exception);
                    });

    System.out.println("main。。。end");
    service.shutdown();

}

运行结果:

2)whenCompleteAsync:是执行把whenCompleteAsync这个任务继续提交给线程池来进行执行

方法不以Async结果,意味着Action使用相同的线程执行,而Async可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)

2.2 exceptionally异常处理

该方法可以捕获异常并给一个返回值。例如;

public static void main(String[] args) throws ExecutionException, InterruptedException {
    System.out.println("main。。。");

    CompletableFuture<Integer> future =
            CompletableFuture.supplyAsync(() -> 10/0, service)
                    .whenComplete((res,exception) -> {
                        System.out.printf("执行的结果是%d,异常信息是%s\r\n",res,exception);
                    })
                    .exceptionally(e ->{
                        System.out.println(e);
                        return -1;
                    });
            ;

    System.out.println("main。。。end  " + future.get());
    service.shutdown();
}

执行结果:

从中可以看出,exceptionally可以捕获异常对其进行处理,同时还可以给一个默认的返回值,而whenComplete方法虽然能得到异常信息,但是没法修改返回的数据,不能给默认的返回值。

3. 最终处理handler方法

handler可以处理执行成功与执行失败的返回

函数定义

public <U> CompletableFuture<U> handle(
        BiFunction<? super T, Throwable, ? extends U> fn) {
    return uniHandleStage(null, fn);
}

public <U> CompletableFuture<U> handleAsync(
        BiFunction<? super T, Throwable, ? extends U> fn) {
    return uniHandleStage(asyncPool, fn);
}

public <U> CompletableFuture<U> handleAsync(
        BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) {
    return uniHandleStage(screenExecutor(executor), fn);
}

和complate一样,可对结果做最后的处理(可处理异常),可改变返回值。

例如:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    System.out.println("main。。。");
    // R apply(T t, U u);
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 10 / 2, service).handleAsync((res, exception) -> {
        if (null == exception) {
            return res * 2;
        } else {
            return -1;
        }
    });

    System.out.println("main。。。end  "+future.get());
    service.shutdown();
}

执行结果:

如果将2改成0,执行结果如图:

4. 线程串行化

4.1 thenApply

当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任务的返回值

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

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

public <U> CompletableFuture<U> thenApplyAsync(
        Function<? super T,? extends U> fn, Executor executor) {
    return uniApplyStage(screenExecutor(executor), fn);
}

 例如:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1启动了");
        return 10 / 5;
    }, service).thenApplyAsync(res -> {
        System.out.println("任务1的结果:" + res);
        return "任务1的结果*10 = " + res * 10;
    }, service);
    System.out.println(future.get());
}

执行结果:

4.2 thenAccept

消费处理结果,接收任务的处理结果,并消费处理,无返回结果

public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
    return uniAcceptStage(null, action);
}

public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) {
    return uniAcceptStage(asyncPool, action);
}

public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
                                               Executor executor) {
    return uniAcceptStage(screenExecutor(executor), action);
}

例如;

public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1启动了");
        return 10 / 5;
    }, service).thenAcceptAsync(res -> {
        System.out.println("线程2启动了,线程1的执行结果:" + res);
    }, service);
}

 执行结果:

4.3 thenRun

只要上面的任务执行完成,就开始执行thenRun,只是处理完任务后,执行thenRun的后续操作

public CompletableFuture<Void> thenRun(Runnable action) {
    return uniRunStage(null, action);
}

public CompletableFuture<Void> thenRunAsync(Runnable action) {
    return uniRunStage(asyncPool, action);
}

public CompletableFuture<Void> thenRunAsync(Runnable action,
                                            Executor executor) {
    return uniRunStage(screenExecutor(executor), action);
}

例如:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1启动了");
        return 10 / 5;
    }, service).thenRun(() -> {
        System.out.println("任务1完成了");
        System.out.println("任务2启动了");
    }, service);
}

执行结果:

注意:因为thenRun没有返回值,因此返回的结果为Void。

5. 两任务组合——都要完成

5.1 thenCombine

组合两个future,获取两个future的返回结果,并返回当前任务的返回值 

public <U,V> CompletableFuture<V> thenCombine(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn) {
    return biApplyStage(null, other, fn);
}

public <U,V> CompletableFuture<V> thenCombineAsync(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn) {
    return biApplyStage(asyncPool, other, fn);
}

public <U,V> CompletableFuture<V> thenCombineAsync(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
    return biApplyStage(screenExecutor(executor), other, fn);
}

例如:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    // 任务1
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1启动了");
        return 10 / 5;
    });
    // 任务2
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务2启动了");
        return "xxx";
    });

    CompletableFuture<String> future = future1.thenCombineAsync(future2, (res1, res2) -> {
        return res1 + "_" + res2;
    }, service);
    System.out.println(future.get());
}

 执行结果:

5.2 thenAcceptBoth

组合两个future,获取两个future的返回值,然后处理任务,没有返回值 

public <U> CompletableFuture<Void> thenAcceptBoth(
        CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action) {
    return biAcceptStage(null, other, action);
}

public <U> CompletableFuture<Void> thenAcceptBothAsync(
        CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action) {
    return biAcceptStage(asyncPool, other, action);
}

public <U> CompletableFuture<Void> thenAcceptBothAsync(
        CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action, Executor executor) {
    return biAcceptStage(screenExecutor(executor), other, action);
}

例如:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    // 任务1
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1启动了");
        return 10 / 5;
    });
    // 任务2
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务2启动了");
        return "xxx";
    });

    future1.thenAcceptBothAsync(future2,(res1,res2)->{
        System.out.println(res1+res2);
    },service);
}

 打印结果:

5.3 runAfterBoth

组合两个future,不需要获取future的结果,只需要两个future处理完任务后,处理该任务。 

public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
                                            Runnable action) {
    return biRunStage(null, other, action);
}

public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
                                                 Runnable action) {
    return biRunStage(asyncPool, other, action);
}

public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
                                                 Runnable action,
                                                 Executor executor) {
    return biRunStage(screenExecutor(executor), other, action);
}

例如:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    // 任务1
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1启动了");
        return 10 / 5;
    });
    // 任务2
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务2启动了");
        return "xxx";
    });
    // 任务1和任务2都完成了执行任务三
    future1.runAfterBothAsync(future1,()->{
        System.out.println("任务3启动了");
    },service);
}

执行结果:

6. 两任务组合-一个完成

当两个任务中,任意一个future任务完成的时候,执行任务

6.1 applyToEither

两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值

public <U> CompletableFuture<U> applyToEither(
        CompletionStage<? extends T> other, Function<? super T, U> fn) {
    return orApplyStage(null, other, fn);
}

public <U> CompletableFuture<U> applyToEitherAsync(
        CompletionStage<? extends T> other, Function<? super T, U> fn) {
    return orApplyStage(asyncPool, other, fn);
}

public <U> CompletableFuture<U> applyToEitherAsync(
        CompletionStage<? extends T> other, Function<? super T, U> fn,
        Executor executor) {
    return orApplyStage(screenExecutor(executor), other, fn);
}

例如:

public static void main(String[] args) throws Exception {
    // 任务1
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1启动了");
        return 10 / 5;
    });
    // 任务2
    CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务2启动了");
        return 20;
    });

    CompletableFuture<String> future = future1.applyToEitherAsync(future2, res -> res + "_哈哈", service);
    String res = future.get();
    System.out.println("任务3的执行结果:" + res);

}

 执行结果:

注意:res的值为任务1和任务2任意一个CompletableFuture的返回值,谁先执行完,res就代表谁的返回值。

6.2 acceptEither

两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值

public CompletableFuture<Void> acceptEither(
        CompletionStage<? extends T> other, Consumer<? super T> action) {
    return orAcceptStage(null, other, action);
}

public CompletableFuture<Void> acceptEitherAsync(
        CompletionStage<? extends T> other, Consumer<? super T> action) {
    return orAcceptStage(asyncPool, other, action);
}

public CompletableFuture<Void> acceptEitherAsync(
        CompletionStage<? extends T> other, Consumer<? super T> action,
        Executor executor) {
    return orAcceptStage(screenExecutor(executor), other, action);
}

注意:acceptEither组合的两个CompletableFuture返回值需要是同类型的。

例如:

public static void main(String[] args) throws Exception {
    // 任务1
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}
        System.out.println("任务1启动了");
        return 10 / 5;
    });
    // 任务3
    CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务2.1启动了");
        return 20;
    });

    future1.acceptEitherAsync(future3,(res) -> {
        Integer newRes = res.intValue() * 5;
        System.out.println("任务3执行的结果:" + newRes);
    },service);
}

执行结果:

6.3 runAfterEither

两个任务有一个执行完成,不需要获取future的结果,处理任务,也没返回值

public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,Runnable action) {
    return orRunStage(null, other, action);
}

public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action) {
    return orRunStage(asyncPool, other, action);
}

public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor) {
    return orRunStage(screenExecutor(executor), other, action);
}

例如:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    // 任务1
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1启动了");
        return 10 / 5;
    });
    // 任务2
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {}
        System.out.println("任务2启动了");
        return "xxx";
    });

    future1.runAfterEitherAsync(future2,()->{
        System.out.println("任务3启动了");
    },service);
}

执行结果:

从执行结果可以看出,任务1和任务2同时执行,任务2睡眠1s,任务1执行完成之后,立马执行任务3.

7. 多任务组合

7.1 allOf

等待所有任务完成

public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
        return andTree(cfs, 0, cfs.length - 1);
    }

例如:

public static void main(String[] args) throws Exception {
    System.out.println("main start...");
    // 任务1
    CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("查询商品属性!");
        return "attr";
    },service);
    // 任务2
    CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("查询商品图片!");
        return "hello.jpg";
    },service);
    // 任务3
    CompletableFuture<String> futureInfo = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("查询商品信息!");
        return "info";
    },service);
    CompletableFuture<Void> allOf = CompletableFuture.allOf(futureAttr, futureImg, futureInfo);
    // allOf.join();
    allOf.get();    // 等待所有结果完成
    System.out.println("main end...");
}

 执行结果:

从结果可以看出 allOf可以组合多个任务,等待所有的任务执行完成之后,在执行主线程

注意:allOf之后需要调用get或者join方法,阻塞等待。

7.2 anyOf

只要有一个任务完成

public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
        return orTree(cfs, 0, cfs.length - 1);
    }

使用方式同allOf方法

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值