异步回调CompletableFuture

在Java8中,出现了可以异步执行并设置回调方法的功能,这对于需要处理耗时很久的任务的应用来说是一件令人振奋的消息。

CompletableFuture不需要你实例化他,他有很多public static 方法直接调用,所以他本身就是一个工具类。

一般来说,我们使用他就需要封装一下,形成自己的工具类,一方面可以更加简单,另一方面可以更加适合自身业务。

总体归纳

实例化

这四个静态的公有方法,返回一个未完成的CompletableFuture实例,supply开头的方法,入参带有返回值的任务,run开头的方法,入参是不带返回值的任务,其中,可以指定自定义的线程池Executor,如果不指定,将使用自带的ForkJoinPool线程池,创建出来的线程都是守护线程,也就是在没有用户线程时,会自动退出,这种我们一般很少用。
supply方法返回一个新的CompletableFuture类实例,接收一个任务Supplier,交给ForkJoinPool进行异步执行,并返回任务的执行结果。
run方法返回一个新的CompletableFuture类实例,接收一个没有返回值的Runnable任务和指定的Executor,任务交给Executor异步执行,完成后无返回值。

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) 
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor)
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor)

同步获取结果

第一个get()方法是阻塞方法,会阻塞到任务完成拿到结果,第二个get(...)方法设置了超时时间,过了指定的等待时间就直接返回了,有可能没有拿到结果。join()放在在任务正确执行时返回任务方法的返回值,当任务方法异常时,返回一个unchecked异常,

public T get() throws InterruptedException, ExecutionException
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
public T join()
​​​​​​​public T getNow(T valueIfAbsent)

设置任务完成后处理方法1-when系

第一个whenComplete(...)接收一个任务结果处理方法,这个方法有2个参数,一个是任务方法的返回值,一个是有异常产生时的异常值,第二个方法的参数和第一个方法参数一模一样,只是第二个方法调用结果处理方法时会异步使用其他线程,而第一个方法调用结果处理方法的线程和处理任务的线程是同一个,异步效率可能会稍微高一点点,第三个方法比第二个方法多一个线程池Executor参数,也就是异步调用结果处理方法时使用指定线程池,第二个方法会使用默认的ForkJoinPool线程池执行结果处理方法,第四个方法是定义一个异常时处理方法,该方法接收一个异常参数,且需要返回一个值,没有值返回可以返回null。注意看这几个方法返回的数据类型都是和任务方法返回的类型一致。

public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) 
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor)
public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)
public static void main(String[] args) {
    // supply系列的任务需要有返回值
    final CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
        log.info("task run");
        return 1;
    }, threadPoolExecutor);
    // when系列的完成方法不能有返回值
    final CompletableFuture<Integer> integerCompletableFuture2 = integerCompletableFuture.whenComplete((result, e) -> {
        log.info("result={}", result);
    });
    // whenAsync使用默认线程池
    integerCompletableFuture.whenCompleteAsync((result, e) -> {
        log.info("result={}", result);
        if (e != null) {
            log.error("", e);
        }
    });
    // whenAsync指定线程池
    integerCompletableFuture.whenCompleteAsync((result, e) -> {
        log.info("result={}", result);
        if (e != null) {
            log.error("", e);
        }
    }, threadPoolExecutor);
}
2022-04-09 14:53:13,430-INFO[peace-thread-1-com.peace.web.util.AsyncUtil:69]-task run
2022-04-09 14:53:13,434-INFO[peace-thread-1-com.peace.web.util.AsyncUtil:74]-result:1
2022-04-09 14:53:13,434-INFO[peace-thread-2-com.peace.web.util.AsyncUtil:85]-result=1
2022-04-09 14:53:13,435-INFO[ForkJoinPool.commonPool-worker-1-com.peace.web.util.AsyncUtil:78]-result=1

设置任务完成后处理方法2-handler系

可以看到handler系列方法和when系列方法的区别是参数类型的差别,handle方式设置的任务完成处理方法,有2个入参,这和when系列一样,不过handler方法需要返回任意类型的返回值,而when系列方法不能有返回值。

public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn)
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor)
public static void main(String[] args) {
    final CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
        log.info("task start");
        int i = 1 / 0;
        return "result";
    }, threadPoolExecutor);
    // handle系列成功处理方法,异步,使用同一线程,返回任意类型
    cf.handle((result, e) -> {
        log.info("result={}", result);
        if (e != null) {
            log.error("", e);
        }
        return 1;
    });
    // handle系列成功处理方法,异步,默认线程池,返回任意类型
    cf.handleAsync((result, e) -> {
        log.info("result={}", result);
        if (e != null) {
            log.error("", e);
        }
        return "";
    });
    // handle系列成功处理方法,异步,指定线程池,返回任意类型
    cf.handleAsync((result, e) -> {
        log.info("result={}", result);
        if (e != null) {
            log.error("", e);
        }
        return new Object();
    }, threadPoolExecutor);
}

结果:

2022-04-09 15:06:49,190-INFO[peace-thread-1-com.peace.web.util.AsyncUtil:94]-task start
2022-04-09 15:06:49,194-INFO[peace-thread-1-com.peace.web.util.AsyncUtil:100]-result=null
2022-04-09 15:06:49,194-INFO[peace-thread-2-com.peace.web.util.AsyncUtil:116]-result=null
2022-04-09 15:06:49,195-INFO[ForkJoinPool.commonPool-worker-1-com.peace.web.util.AsyncUtil:108]-result=null
2022-04-09 15:06:49,195-ERROR[peace-thread-1-com.peace.web.util.AsyncUtil:102]-
java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315)
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1770)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ArithmeticException: / by zero
	at com.peace.web.util.AsyncUtil.lambda$main$5(AsyncUtil.java:95)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)
	... 3 common frames omitted
2022-04-09 15:06:49,195-ERROR[ForkJoinPool.commonPool-worker-1-com.peace.web.util.AsyncUtil:110]-
java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315)
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1770)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ArithmeticException: / by zero
	at com.peace.web.util.AsyncUtil.lambda$main$5(AsyncUtil.java:95)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)
	... 3 common frames omitted
2022-04-09 15:06:49,195-ERROR[peace-thread-2-com.peace.web.util.AsyncUtil:118]-
java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315)
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1770)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ArithmeticException: / by zero
	at com.peace.web.util.AsyncUtil.lambda$main$5(AsyncUtil.java:95)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)
	... 3 common frames omitted

设置任务完成后处理方法3-apply系

handle系列任务完成处理方法,处理方法接收任务结果,不接受异常,可以返回任意类型数据,如果任务发生异常,会被忽略。

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn);
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn);
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor);
public static void main(String[] args) {
    final CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
        log.info("task start");
        int i = 1 / 0;
        return "result";
    }, threadPoolExecutor);

    // apply系列完成处理方法,使用任务同一线程处理,只接收1个任务结果,不接收异常,但是如果任务有异常被忽略
    cf.thenApply((result) -> {
        log.info("result={}", result);
        return "";
    });

    // apply系列完成处理方法,使用默认线程池异步处理,只接收1个任务结果,不接收异常,但是如果任务有异常被忽略
    cf.thenApplyAsync((result) -> {
        log.info("result={}", result);
        return 2;
    });

    // apply系列完成处理方法,使用指定线程池异步处理,只接收1个任务结果,不接收异常,但是如果任务有异常被忽略
    cf.thenApplyAsync((result) -> {
        log.info("result={}", result);
        return new Object();
    }, threadPoolExecutor);

}

设置任务完成后处理方法4-accept系 

accept系列任务完成处理方法,处理方法接收任务处理结果数据,不接收异常,不返回数据,任务有异常也被忽略。

public static void main(String[] args) {
    final CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
        log.info("task start");
        int i = 1 / 0;
        return "result";
    }, threadPoolExecutor);

    // accept系列完成处理方法,使用任务同一线程处理,只接收1个任务结果,不返回数据,不接收异常,但是如果任务有异常被忽略
    cf.thenAccept((result) -> {
        log.info("result={}", result);
    });

    // apply系列完成处理方法,使用默认线程池异步处理,只接收1个任务结果,不返回数据,不接收异常,但是如果任务有异常被忽略
    cf.thenAcceptAsync((result) -> {
        log.info("result={}", result);
    });

    // apply系列完成处理方法,使用指定线程池异步处理,只接收1个任务结果,不返回数据,不接收异常,但是如果任务有异常被忽略
    cf.thenAcceptAsync((result) -> {
        log.info("result={}", result);
    }, threadPoolExecutor);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值