CompletableFuture异步编程

一、创建CompletableFuture的方式

1、同步
// 使用构造方法
CompletableFuture<String> cf = new CompletableFuture<>();
cf.complete("result");

// 已知返回结果,静态方法(底层带参数的构造器赋值)
CompletableFuture<String> cf = CompletableFuture.completedFuture("result");
2、异步
ExecutorService executor = Executors.newSingleThreadExecutor();

// 无返回值,默认使用ForkJoinPool线程池
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {});

// 无返回值,指定线程池
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {}, executor);

// 有返回值,默认使用ForkJoinPool线程池
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> "result");

// 有返回值,指定线程池
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> "result", executor);

二、获取异步执行结果

1、get()
// 阻塞式获取,需要处理受检异常
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
    return "result";
});     
try {
    String result = cf.get();
} catch (InterruptedException e) {
    throw new RuntimeException(e);
} catch (ExecutionException e) {
    throw new RuntimeException(e);
}
2、get(long timeout, TimeUnit unit)
// 带超时时间的阻塞式获取,超时抛出TimeoutException,同样需要手动处理受检异常
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
    return "result";
});     
try {
    String result = cf.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    System.out.println("超时");
} catch (ExecutionException e) {
    throw new RuntimeException(e);
} catch (InterruptedException e) {
    throw new RuntimeException(e);
}
3、join()
// 阻塞式获取,跟get()一样,但不会抛出受检异常
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
    return "result";
});     
String result = cf.join()
4、getNow(T valueIfAbsent)
// 立即获取当前执行结果,如果任务没完成则返回valueIfAbsent传入的值
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
    return "result";
});     
String result = cf.getNow("result2")

三、对执行结果进行处理

// 说明
xxx() 如果注册时被依赖的操作已经执行完成,则直接由当前线程执行、如果注册时被依赖的操作还未执行完,则由回调线程执行。

xxxAsync() 使用从默认线程(ForkJoinPool 线程池)执行当前任务

xxxAsync(Executor executor) 使用自己指定的线程池执行当前任务
1、thenRun() - 串行
// thenRunAsync()、thenRunAsync(Executor executor)
// 前面任务执行完后执行当前任务,不关心前面任务的结果,也没返回值
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> "result1");
cf.thenRun(() -> {
    System.out.println("结束后执行");
    System.out.println(Thread.currentThread().getName());
});
2、thenAccept() - 串行
// thenAcceptAsync()、thenAcceptAsync(Executor executor)
// 前面任务执行完后执行当前任务,消费前面的结果,没有返回值
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> "result1");
cf.thenAccept(res -> {
    System.out.println(res);
    System.out.println(Thread.currentThread().getName());
});
3、thenApply() - 串行
// thenApplyAsync()、thenApplyAsync(Executor executor)
// 前面任务执行完后执行当前任务,消费前面的结果,有返回值
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> "result1");
cf.thenApply(res -> {
    System.out.println(res);
    System.out.println(Thread.currentThread().getName());
    return "result2";
}).whenComplete((res, ex) -> {
    System.out.println(res);
});
4、whenComplete() - 异常处理
// whenCompleteAsync()、whenCompleteAsync(Executor executor)
// 等待前面任务执行完再执行当前处理,也可以作为异常处理使用
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> "result1");
cf.whenComplete((res, ex) -> {
    System.out.println("执行结果: " + res);
    System.out.println(Thread.currentThread().getName());
    ex.printStackTrace();
});
5、handle()、exceptionally() - 异常处理
/**
 * handleAsync()、handleAsync(Executor executor)
 * exceptionally() 异常捕获,只消费前面任务中出现的异常信息,有返回值
 * handle() 异常处理,消费前面的结果及异常信息,有返回值,不会中断后续任务
 * handle需要对异常进行判空检查
 * 如果只专注于异常处理,选择exceptionally(),它可以简化了输入参数,并且可以避免异常空检查的if语句。
 * 如果希望不影响主流程,也不加try进行捕获,使用handle()方法,它可以从异常中恢复过来。
 */
CompletableFuture.supplyAsync(() -> {
    int a = 1 / 0;
    return "result1";
}).exceptionally(ex -> {
    System.out.println(ex);
    return "error";
}).handle((res, ex) -> {
    System.out.println(res);
    System.out.println(ex);
    return "handle";
}).thenAccept(res -> {
    System.out.println(res);
});
6、thenCompose() - 串行
// thenComposeAsync()、thenComposeAsync(Executor executor)
// 实现两组任务按前后顺序执行(耗时为两个任务的耗时之和)
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(3000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result1";
});
StopWatch sw = StopWatch.createStarted();
CompletableFuture<String> cm = cf1.thenCompose(res -> {
    System.out.println(res);
    return CompletableFuture.supplyAsync(() -> {
        try {
            TimeUnit.MILLISECONDS.sleep(6000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return res + "result2";
    });
});
System.out.println(cm.join());
System.out.println("耗时:" + sw.getTime(TimeUnit.MILLISECONDS));
7、applyToEither() - OR汇聚
// applyToEitherAsync()、applyToEitherAsync(Executor executor)
// 比较两组任务执行速度,谁快消费谁的执行结果
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(4000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result1";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(3000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result2";
});
StopWatch sw = StopWatch.createStarted();
CompletableFuture<String> cm = cf1.applyToEither(cf2, (res) -> {
    return res;
});
System.out.println(cm.join());
System.out.println("耗时:" + sw.getTime(TimeUnit.MILLISECONDS));
8、runAfterEither() - OR汇聚
// runAfterEitherAsync()、runAfterEitherAsync(Executor executor)
// 这个方法效果和上面的一样,不同的是这个方法不消费结果也没有返回值
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(4000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result1";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(3000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result2";
});
StopWatch sw = StopWatch.createStarted();
CompletableFuture<Void> cm = cf1.runAfterEither(cf2, () -> {
    System.out.println("执行结束了");
});
cm.join();
System.out.println("耗时:" + sw.getTime(TimeUnit.MILLISECONDS));
9、thenCombine() - AND汇聚
// thenCombineAsync()、thenCombineAsync(Executor executor)
// 等待两组任务执行完毕,合并执行结果(耗时为最长任务的耗时)

CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(3000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result1";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(6000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result2";
});
StopWatch sw = StopWatch.createStarted();
CompletableFuture<String> cm = cf1.thenCombine(cf2, (res1, res2) -> {
    return res1 + res2;
});
String result = cm.join();
System.out.println(result);
System.out.println("耗时:" + sw.getTime(TimeUnit.MILLISECONDS));
10、runAfterBoth() - AND汇聚
// runAfterBothAsync()、runAfterBothAsync(Executor executor)
// 这个方法效果和上面的一样,不同的是这个方法不消费结果也没有返回值
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(3000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result1";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(6000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result2";
});
StopWatch sw = StopWatch.createStarted();
CompletableFuture<Void> cm = cf1.runAfterBoth(cf2, () -> {
    System.out.println("执行结束");
});
cm.join();
System.out.println("耗时:" + sw.getTime(TimeUnit.MILLISECONDS));
11、多任务组合
// 实现并行地执行多个任务,等待所有任务执行完成(无需考虑执行顺序),耗时为最长任务的耗时
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(1000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result1";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(2000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result2";
});
CompletableFuture<String> cf3 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(3000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result3";
});
StopWatch sw = StopWatch.createStarted();
CompletableFuture<Void> cf = CompletableFuture.allOf(cf1, cf2, cf3);
cf.join();
System.out.println(cf1.join());
System.out.println(cf2.join());
System.out.println(cf3.join());
System.out.println("耗时:" + sw.getTime(TimeUnit.MILLISECONDS));

// 实现并行地执行多个任务,只要有个一个完成的便会返回执行结果,耗时为最短任务的耗时
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(1000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result1";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(2000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result2";
});
CompletableFuture<String> cf3 = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(3000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return "result3";
});
StopWatch sw = StopWatch.createStarted();
CompletableFuture<Object> cf = CompletableFuture.anyOf(cf1, cf2, cf3);
Object result = cf.join();
System.out.println(result);
System.out.println("耗时:" + sw.getTime(TimeUnit.MILLISECONDS));

四、练习

    /**
     * 三个任务的并发执行,A、B同时执行,全部执行完成后执行C
     * 耗时: 任务A 1000ms、任务B 2000ms、任务C 3000ms
     * 目标结果: A+B+C
     * 目标耗时: MAX(A, B) + C = 5000ms
     */
    @Test
    public void test1() {
        CompletableFuture<String> cfA = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "result A";
        });
        CompletableFuture<String> cfB = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "result B";
        });
        CompletableFuture<String> cfC = cfA.thenCombine(cfB, (a, b) -> {
            try {
                TimeUnit.MILLISECONDS.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return a + ":" + b + ":" + "resultC";
        });
        StopWatch sw = StopWatch.createStarted();
        System.out.println(cfC.join());
        System.out.println("总耗时: " + sw.getTime(TimeUnit.MILLISECONDS) + "ms");
    }

输出结果:
result A:result B:resultC
总耗时: 5011ms
/**
     * 完成三个任务的并发执行,A、B同时执行,任意一个任务执行完成后执行C
     * 耗时: 任务A 1000ms、任务B 1000ms、任务C 3000ms
     * 目标结果: (A or B)+C
     * 目标耗时: 1000ms + C = 4000ms
     */
    @Test
    public void test2() {
        CompletableFuture<String> cfA = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "result A";
        });
        CompletableFuture<String> cfB = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "result B";
        });

        CompletableFuture<String> cfC = cfA.applyToEither(cfB, res -> {
            try {
                TimeUnit.MILLISECONDS.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return res + ":" + "resultC";
        });
        StopWatch sw = StopWatch.createStarted();
        System.out.println(cfC.join());
        System.out.println("总耗时: " + sw.getTime(TimeUnit.MILLISECONDS) + "ms");
    }
输出结果:
result A:resultC
总耗时: 4009ms
/**
     * 完成四个任务的并发执行,A、B、C同时执行,任意一个任务执行完成后执行D
     * 耗时: 任务A 1000ms、任务B 1000ms、任务C 1000ms、任务D 2000ms
     * 目标结果: (A or B or C)+D
     * 目标耗时: 1000ms + D = 3000ms
     */
    @Test
    public void test3() {
        CompletableFuture<String> cfA = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "result A";
        });
        CompletableFuture<String> cfB = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "result B";
        });
        CompletableFuture<String> cfC = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "result C";
        });

        CompletableFuture<String> cfD = CompletableFuture.anyOf(cfA, cfB, cfC).thenApply(res -> {
            try {
                TimeUnit.MILLISECONDS.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return res + ":" + "resultD";
        });
        StopWatch sw = StopWatch.createStarted();
        System.out.println(cfD.join());
        System.out.println("总耗时: " + sw.getTime(TimeUnit.MILLISECONDS) + "ms");
    }
输出结果:
result A:resultD
总耗时: 3009ms
    /**
     * 完成四个任务的并发执行,A、B、C同时执行,全部任务执行完成后执行D
     * 耗时: 任务A 1000ms、任务B 2000ms、任务C 3000ms、任务D 2000ms
     * 目标结果: A+B+C+D
     * 目标耗时: MAX(A, B, C)+D = 5000ms
     */
    @Test
    public void test4() {
        CompletableFuture<String> cfA = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "result A";
        });
        CompletableFuture<String> cfB = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "result B";
        });
        CompletableFuture<String> cfC = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "result C";
        });

        CompletableFuture<String> cfD = CompletableFuture.allOf(cfA, cfB, cfC).thenApply(res -> {
            try {
                TimeUnit.MILLISECONDS.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            String a = cfA.join();
            String b = cfB.join();
            String c = cfC.join();
            return a + ":" + b + ":" + c + ":" + "resultD";
        });
        StopWatch sw = StopWatch.createStarted();
        System.out.println(cfD.join());
        System.out.println("总耗时: " + sw.getTime(TimeUnit.MILLISECONDS) + "ms");
    }
输出耗时:
result A:result B:result C:resultD
总耗时: 4997ms
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值