Lambda从入门到精通之二十九 使用CompletableFuture异步编程

Future设计目的是为了实现异步计算,具体原理和使用方式前面的内容已经讲过,CompletableFuture同样是用来进行异步编程的,CompletableFuture相较于Future,更能更加强大,CompletableFuture的出现就是为了解决Future的不足才设计的。
CompletableFuture能够非常容易地将多个计算任务以同步或异步方式执行,并将任务结合到一起,实现多个异步计算的关联计算等复杂功能。
我们来看一个简单的入门demo,demo的功能是查询多个商品的价格,但是其中某个商品的价格获取非常耗时,所以采用了CompletableFuture异步计算,看代码:

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class FutureTest_2 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //进行异步价格计算
        Future<Integer> priceA = getPriceAsync();

        //执行其他业务逻辑
        printOtherPrice();

        //获取价格计算结果
        Integer price = priceA.get();
        System.out.println("异步获取价格" + price);

    }

    public static void printOtherPrice() {
        for(int i=0; i<10; i++) {
            System.out.println("获取其他商品价格:"  + new Random().nextInt());
        }
    }

    public static Future<Integer> getPriceAsync() {
        CompletableFuture<Integer> future = new CompletableFuture<>();
        new Thread(()->{
            try {
                //模拟计算复杂逻辑
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            future.complete(new Random().nextInt());
        }).start();
        return future;
    }
}
/* 输出
获取其他商品价格:450142711
获取其他商品价格:-1207991723
获取其他商品价格:-264920736
获取其他商品价格:1122276343
获取其他商品价格:-652082111
获取其他商品价格:1312307709
获取其他商品价格:-417893410
获取其他商品价格:1957242712
获取其他商品价格:1257272721
获取其他商品价格:100803481
异步获取价格-1514711276
 */

demo中的第一行代码,调用getPriceAsync方法计算价格,返回了一个Future对象。getPriceAsync方法中创建了一个CompletableFuture类型的变量并作为返回结果,同时直接就返回了,我们可以看到程序另外启动了一个线程去计算价格,价格计算完成会将结果赋值给CompletableFuture,这就好像是一个钩子,让独立启动的线程和这个future关联了起来,这样发起调用的程序(Future priceA = getPriceAsync()),拿着这个CompletableFuture变来那个,就可以在想要执行的位置获取异步执行的方法的执行结果。
上面的内容对应的就是
1、进行异步价格计算,获取一个异步结果的变量

Future<Integer> priceA = getPriceAsync();

2、getPriceAsync方法中计算并建立和外部Future priceA变量的关联

public static Future<Integer> getPriceAsync() {
	//创建一个异步变量
	CompletableFuture<Integer> future = new CompletableFuture<>();
	
	//发起一个线程去计算
	new Thread(()->{
		try {
			//模拟计算复杂逻辑
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		//这里将计算结果赋值给这个异步变量
		future.complete(new Random().nextInt());
	}).start();
	
	//这里返回是不等新的线程执行完的,new完CompletableFuture<Integer>就直接返回了
	return future;
}

这里有的同学可能会有疑惑:
//这里将计算结果赋值给这个异步变量
future.complete(new Random().nextInt());
为什么new Thread能看到它上面的future变量并使用,这是线程可见性的原因,被new出来的线程,能够看见new它的线程之前干的事情,所以new Thread中可以直接引用这个future。

3、在上面执行复杂计算的同时,可以执行其他业务逻辑
printOtherPrice();

4、获取价格计算结果
Integer price = priceA.get();
System.out.println(“异步获取价格” + price);
这里priceA.get()方法会一直等待结果返回