Java 异步计算

CompletableFuture(可完成的Future)

一个可完成的Future,在我们调用他的get方法的时候,他会阻塞等待这个任务完成来获取他的结果。
当然也可以为这个任务注册一些回调,类似于完成时,出现异常时,或者执行超时等额外处理。

使用

CompletableFuture.suppleAsync

异步执行一个任务并返回结果

CompletableFuture.runAsync

异步执行一个任务不返回结果

这两方法都可以为我们快速的创建一个CompletableFuture对象

CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
    System.out.println(Thread.currentThread().getName() + ":supplyAsync start");
    return "supplyAsync";
});

CompletableFuture<String> completableFuture = CompletableFuture.runAsync(() -> {
    System.out.println(Thread.currentThread().getName() + ":runAsync start");
    return "runAsync";
});

这两个方法都是可以有第二个参数的,也就是可以执行线程池,这里默认是**Fork-Join-Pool**(一个可以将一个大任务很自然的分解为多个子任务的线程池)。

回调有哪些

方法参数描述
thenApplyT -> U对结果进行处理,并返回一个新的结果
thenAccpetT -> void对结果进行处理,返回结果为Void
thenComposeT -> CompletableFuture对结果调用这个函数来进行处理,并返回一个新的结果
handle(T,Throwable) -> U与thenApply类似,但是他可以处理异常,根据异常对象是否为null,可以判断是否出现异常。
不报错也会执行
whenCompletable(T,Throwable) -> void类似handle 但是不返回结果
不报错也会执行
exceptionallyThrowable -> U出现异常时,返回一个结果
报错时才会执行。
completableOnTimeoutT, long, TimeUnit如果超时返回一个指定的结果。
超时后的链式操作都不执行
orTimeoutlong, TimeUnit超时返回一个异常 TimeOutException
超时后的链式操作都不执行
thenRunRunable执行Runable,返回void,对于不需要任务的返回结果

示例

private static final ThreadPoolExecutor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(10, 10, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(50));


public static void main(String[] args) {
    CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread().getName() + ":supplyAsync");
        return "supplyAsync";
    });
	
    completableFuture
            .thenApply((result) -> {
                System.out.println(Thread.currentThread().getName() + ":thenApply1 ");
                return result + "\nthenApply1";
            })
            .thenAccept((result) -> {
                System.out.println(Thread.currentThread().getName() + ":thenAccept ");
            })
            .thenCompose(result ->
                    CompletableFuture.supplyAsync(() -> {
                        try {
                            System.out.println(Thread.currentThread().getName() + ":thenCompose ");
                            TimeUnit.SECONDS.sleep(2);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        return result + "\nthenCompose";
                    })
            )
            // thenCompose 超时了,orTimeout 之前的的操作都将被忽略 之后的还会执行
   			.thenAccept((result) -> {
                    System.out.println(Thread.currentThread().getName() + ":ignore ");
                })
            // .completeOnTimeout("completeOnTimeout", 1, TimeUnit.SECONDS)
            // 这里会抛出一个TimeOutException
            .orTimeout(1, TimeUnit.SECONDS)
            // throwable则可以获取到 TimeOutException 
            .handleAsync((result, throwable) -> {
                System.out.println(Thread.currentThread().getName() + ":handleAsync  ");
                if (throwable == null) {
                    return result;
                }
                throwable.printStackTrace();
                return result + "\nhandleAsync";
            }, THREAD_POOL_EXECUTOR)
            // 因为TimeOutException 被handleAsync处理了,所以这里也没有异常了throwable为null
            .whenComplete((result, throwable) -> {
                System.out.println(Thread.currentThread().getName() + ":whenComplete  ");
                if (throwable == null) {
                    return;
                }
                throwable.printStackTrace();
            })
            .thenRun(() -> {
                    System.out.println(Thread.currentThread().getName() + ":thenRun ");
            });

    try {
        Thread.sleep(5000); // 添加短暂的延迟  因为是异步任务这里不等待一下的话main线程就终止了
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    THREAD_POOL_EXECUTOR.shutdownNow();
}


#### 执行结果
ForkJoinPool.commonPool-worker-3:supplyAsync
ForkJoinPool.commonPool-worker-3:thenApply1 
ForkJoinPool.commonPool-worker-3:thenAccept 
ForkJoinPool.commonPool-worker-3:thenCompose 
pool-1-thread-1:handleAsync  
pool-1-thread-1:whenComplete  
pool-1-thread-1:thenRun 
java.util.concurrent.TimeoutException

注意回调时机即可。

Async回调

我们这里使用一个叫handleAsync的方法与普通的handle相比,他是执行的线程发送了变化。
使用Async在大多数情况下都会是在一个新的线程下去帮我们执行这个回调,而普通的则是在原有由原有执行任务的线程去执行这个回调。
这里的大多数情况是指我们在使用自定义线程池的时候。而我们的Fork-Join-Pool可能会为一些短暂的任务重用相同的线程,以减少线程的创建和销毁开销。

get、join

当我们的CompletableFuture提供了返回值的时候,我们可以通过get或者join方法来阻塞的得到这个结果
与之不同是get他可能会抛出异常,而join不会。通常我们使用join

组合CompletableFuture

可以根据某种条件去执行两个或者多个CompletableFuture
因为组合太多,这里就简单描述下我自己比较常用的

方法参数描述
static allOfCompletableFuture<?>…所以任务都执行完成后完成,返回结果为void
static anyOfCompletableFuture<?>…任意任务都执行完成后完成,返回结果为void

示例

public static void main(String[] args) {
    // 1.两个任务都执行完成后才完成
    CompletableFuture.allOf(CompletableFuture.runAsync(()->{
        System.out.println("supplyAsync1");
    }),CompletableFuture.runAsync(()->{
        // 异步任务等待1秒
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("supplyAsync2");
    }));

    // 任意一个完成则完成
    CompletableFuture.anyOf(CompletableFuture.runAsync(()->{
        System.out.println("supplyAsync3");
    }),CompletableFuture.runAsync(()->{
        // 异步任务等待2秒
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("supplyAsync4");
    }));
	// 主线程只等待一秒 
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

### 结果
supplyAsync1
supplyAsync3
supplyAsync2

allOf 因为需要两个都完成所以等待一秒后完成输出supplyAsync1、supplyAsync2
antOf 任意一个完成则算结束。因为第二个等待两秒,主线程已经结束了,main已经退出了,所以只输出supplyAsync3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

假女吖☌

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

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

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

打赏作者

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

抵扣说明:

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

余额充值