JUC并发编程 CompletableFuture 常用方法 (一)
1 get()
用get()方法来获取线程计算结果的返回值
@SneakyThrows
public static void future(){
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName() + "----come in");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(5);
}catch (InterruptedException e){
e.printStackTrace();
}
return result;
});
//不见不散,非要等到结果才会离开,不管你是否计算完成,容易造成程序堵塞
System.out.println(completableFuture.get());
System.out.println(Thread.currentThread().getName() + "线程先去忙其它任务");
}
1 从上述程序中我们可以看出,当我们使用get()方法获取线程的计算结果,必须要等到线程计算完毕,和FutureTask一样,还是阻塞了。
2 get()方法容易阻塞,一般建议放在程序后面,一旦调用不见不散,非要等到结果才会离开,不管你是否计算完成,容易程序堵塞。
2 get(long timeout,TimeUnit unit)
上面get()必须要等到线程计算完,假如我不想等待呢?可以用get(long timeout,TimeUnit unit)方法
@SneakyThrows
public static void future1(){
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName() + "----come in");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(3);
}catch (InterruptedException e){
e.printStackTrace();
}
return result;
});
System.out.println(completableFuture.get(2,TimeUnit.SECONDS));
System.out.println(Thread.currentThread().getName() + "线程先去忙其它任务");
}
3 whenComplete
当线程计算完成时 会回调此方法
@SneakyThrows
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName() + "----come in");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("-----1秒钟后出结果:"+result);
return result;
//如果完成 v = result 的返回值 e = exception
},executorService).whenComplete((v,e)->{
//如果没有异常
if(e == null){
System.out.println("-----计算完成,更新系统UpdateValue: "+v);
}
});
System.out.println(Thread.currentThread().getName() + "线程先去忙其它任务");
executorService.shutdown();
}
从上图的执行顺序我们可以看出,当我们获取线程计算的返回值时,并不需要像get()方法那样等到线程执行完毕才往下走,而是线程执行完毕会主动回调,触发whenComplete
4 exceptionally
上面程序执行正常会回调whenComplete方法,那么当程序执行异常呢?会回调exceptionally方法
@SneakyThrows
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName() + "----come in");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
//模拟异常
int i = 10/0;
System.out.println("-----1秒钟后出结果:"+result);
return result;
//如果完成 v = result 的返回值 e = exception
},executorService).whenComplete((v,e)->{
//如果没有异常
if(e == null){
System.out.println("-----计算完成,更新系统UpdateValue: "+v);
}
}).exceptionally(e->{
e.printStackTrace();
System.out.println("异常情况:"+e.getCause()+"\t"+e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + "线程先去忙其它任务");
executorService.shutdown();
}
5 总结
从上面的例子中我们发现,CompletableFuture 不仅有FutureTask中的get() 和 get(long timeout,TimeUnit unit) 方法,还扩展了一些会回调的方法,非常好用,简直是业务代码异步编程神器。
CompletableFuture优点:
- 异步任务结束时,会自动回调某个对象的方法
- 主线程设置好回调后,不用关心异步任务的执行,异步任务之间可以顺序执行
- 异步任务出错时,会自动回调某个对象的方法