CompletableFuture: 组合式异步编程

1.先了解下什么是吞吐量:

吞吐量是指对网络、设备、端口、虚电路或其他设施,单位时间内成功地传送数据的数量(以比特字节、分组等测量)。(百科)

2.并发,并行:

并发:单个处理器核在多个任务之间切换处理

并行:多个处理器核同时处理多个任务

java并发量高怎么处理 java并发量怎么算的_主线程

Future 接口

Future接口建模了一种异步计算,返回一个执行运算结果的引用,当运算结束后,这个运用hui被返回调用方。

(简单说就是你去奶茶店排队买奶茶,店员给你一个序号,你就不用在那里等待,可以去做其他事,等好了再去拿,这就是异步)

例子:

ExecutorService executor = Executors.newCachedThreadPool(); 
Future<Double> future = executor.submit(new Callable<Double>() { 
 public Double call() {
 return doSomeLongComputation(); 
 }}); 
doSomethingElse();
try { 
 Double result = future.get(2, TimeUnit.SECONDS); 
} catch (Exception e) {
 // 计算抛出一个异常
}


        这种编程方式让你的线程可以在 ExecutorService 以并发方式调 用另一个线程执行耗时操作的同时,去执行一些其他的任务。接着,如果你已经运行到没有异步 操作的结果就无法继续任何有意义的工作时,可以调用它的get 方法去获取操作的结果。如果操 作已经完成,该方法会立刻返回操作的结果,否则它会阻塞你的线程,直到操作完成,返回相应 的结果。


       Feature 使用重 载版本的get 方法,它接受一个超时的参数,通过它,你可以定义你的线程等待 Future 结果的最 长时间,而不是一直等待下去




java并发量高怎么处理 java并发量怎么算的_异步操作_02


使用 CompletableFuture 构建异步应用


       我们知道 Future 接口提供了方法来检测异步计算是否已经结束(使用 isDone方法),等待异步操作结束,以及获取计算的结果。但是这些特性还不足以让你编写简洁 的并发代码。比如,我们很难表述Future 结果之间的依赖性;从文字描述上这很简单,“当长时 间计算任务完成时,请将该计算的结果通知到另一个长时间运行的计算任务,这两个计算任务都 完成后,将计算的结果与另一个查询操作结果合并”。但是,使用Future 中提供的方法完成这样 的操作又是另外一回事。这也是我们需要更具描述能力的特性的原因,比如下面这些。


         将两个异步计算合并为一个 —— 这两个异步计算之间相互独立,同时第二个又依赖于第 一个的结果。


         等待 Future 集合中的所有任务都完成。


         仅等待 Future 集合中最快结束的任务完成(有可能因为它们试图通过不同的方式计算同 一个值),并返回它的结果。


         通过编程方式完成一个 Future 任务的执行(即以手工设定异步操作结果的方式)。


         应对 Future 的完成事件(即当 Future 的完成事件发生时会收到通知,并能使用 Future


      计算的结果进行下一步的操作,不只是简单地阻塞等待操作的结果)。下面你会了解新的CompletableFuture 类(它实现了 Future 接口)如何利用 Java 8 的新特性以更直观的方式将上述需求都变为可能。Stream 和 CompletableFuture 的设计都遵循


了类似的模式:它们都使用了 Lambda 表达式以及流水线的思想。从这个角度,你可以说 CompletableFuture和 Future 的关系就跟 Stream 和 Collection 的关系一样。


(1)runAsync方法: 异步创建一个简单的没有返回值的Future


ExecutorService executorService = Executors.newCachedThreadPool();

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {

            System.out.println(Thread.currentThread().getName());
        }, executorService);

        System.out.println("主线程: " + Thread.currentThread().getName());
        future.get(2, TimeUnit.SECONDS);

结果:

主线程: main
pool-1-thread-1

(2)supplyAsync方法: 异步创建一个有返回值的CompleteFuture

ExecutorService executorService = Executors.newCachedThreadPool();

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {

            System.out.println(Thread.currentThread().getName());
            return 4;
        }, executorService);

        System.out.println("主线程: " + Thread.currentThread().getName());
        Integer integer = future.get(2, TimeUnit.SECONDS);
        System.out.println(integer);

结果:

主线程: main
pool-1-thread-1
4

(3)thenApply, thenAccept, thenRun,这三个都是同步操作

thenApply() 监听future返回,调用Future方法对返回值业务逻辑操作,这个操作有返回值,比如转换类型

thenAccept() 监听future返回,调用Consumer处理返回值,处理的结果没有返回值,比如打印结果,返回值为CompletableFuture<void>

thenRun() 监听future返回,然后自己自定义处理,返回值为CompletableFuture<void>

ExecutorService executorService = Executors.newCachedThreadPool();

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {

            System.out.println(Thread.currentThread().getName());
            return 4;
        }, executorService).thenApply(f ->{
            
            System.out.println(Thread.currentThread().getName());
            System.out.println("thenApply: + " + f);
            return String.valueOf(f) + "aaa";
        });
        
        CompletableFuture<Void> voidCompletableFuture = future.thenAccept(f -> {
            System.out.println(Thread.currentThread().getName());
            System.out.println("thenAccept: + " + f);
        });

        CompletableFuture<Void> voidCompletableFuture1 = voidCompletableFuture.thenRun(() -> {
            System.out.println(Thread.currentThread().getName());
            System.out.println("thenRun: + ");
        });

        System.out.println("主线程: " + Thread.currentThread().getName());
        String integer = future.get(2, TimeUnit.SECONDS);
        System.out.println(integer);
pool-1-thread-1
主线程: main
pool-1-thread-1
thenApply: + 4
pool-1-thread-1
thenAccept: + 4aaa
pool-1-thread-1
thenRun: + 
4aaa

(4)thenApplyAsync, thenAcceptAsync, thenRunAsync,同上面三个对应,是异步操作

ExecutorService executorService = Executors.newCachedThreadPool();

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {

            System.out.println(Thread.currentThread().getName());
            return 4;
        }, executorService).thenApplyAsync(f ->{

            System.out.println(Thread.currentThread().getName());
            System.out.println("thenApply: + " + f);
            return String.valueOf(f) + "aaa";
        }, executorService);

        CompletableFuture<Void> voidCompletableFuture = future.thenAcceptAsync(f -> {
            System.out.println(Thread.currentThread().getName());
            System.out.println("thenAccept: + " + f);
        }, executorService);

        CompletableFuture<Void> voidCompletableFuture1 = voidCompletableFuture.thenRunAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            System.out.println("thenRun: + ");
        }, executorService);

        System.out.println("主线程: " + Thread.currentThread().getName());
        String integer = future.get(2, TimeUnit.SECONDS);
        System.out.println(integer);
pool-1-thread-1
pool-1-thread-1
thenApply: + 4
pool-1-thread-1
thenAccept: + 4aaa
主线程: main
pool-1-thread-1
thenRun: + 
4aaa

注意:这里是同一个线程,主要是因为这里线程池我用的是可缓存的线程池,线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。我们可以让线程睡眠一点时间

修改下代码:

ExecutorService executorService = Executors.newCachedThreadPool();

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
            return 4;
        }, executorService).thenApplyAsync(f ->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
            System.out.println("thenApply: + " + f);
            return String.valueOf(f) + "aaa";
        }, executorService);

        CompletableFuture<Void> voidCompletableFuture = future.thenAcceptAsync(f -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
            System.out.println("thenAccept: + " + f);
        }, executorService);

        CompletableFuture<Void> voidCompletableFuture1 = voidCompletableFuture.thenRunAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
            System.out.println("thenRun: + ");
        }, executorService);

        System.out.println("主线程: " + Thread.currentThread().getName());
        String integer = future.get(4, TimeUnit.SECONDS);
        voidCompletableFuture.get();
        voidCompletableFuture1.get();
        System.out.println(integer);
主线程: main
pool-1-thread-1
pool-1-thread-2
thenApply: + 4
pool-1-thread-1
thenAccept: + 4aaa
pool-1-thread-2
thenRun: + 
4aaa

可以看到还是存在有些线程已经完成并且被复用了,可以再试试把睡眠时间调整为不一样试试。

(3) thenCompose方法 多层结构的future返回一个结果,跟java8的flatmap差不多

CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
            return 4;
        }, executorService).thenCompose(f -> CompletableFuture.supplyAsync(() -> f + "dddd", executorService));

        System.out.println(stringCompletableFuture.get());
pool-1-thread-2
4dddd

(4)thenCombine与thenAcceptBoth, 合并两个future,thenCombine有返回值,thenAcceptBoth没有返回值

ExecutorService executorService = Executors.newCachedThreadPool();
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
            return 4;
        }, executorService);
        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
            return 5;
        }, executorService);
        CompletableFuture<Integer> f3 = f1.thenCombine(f2, (s1, s2) -> {
            System.out.println(String.format("%d,%d", s1, s2));
            return s1 + s2;
        });
        System.out.println(f3.get());

        CompletableFuture<Void> f4 = f1.thenAcceptBoth(f2, (s1, s2) -> {
            System.out.println(String.format("%d,%d", s1, s2));
        });
        System.out.println(f4.get());
pool-1-thread-1
pool-1-thread-2
4,5
9
4,5
null

(5) allOf   anyOf  

allOf   CompleteableFuture数组里面全部完成才返回结果

ExecutorService executorService = Executors.newCachedThreadPool();
        List<CompletableFuture<String>> list = IntStream.rangeClosed(0, 10).mapToObj(i -> CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(i * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "sleep :" + i * 1000 + "s");
            return i + "s";
        }, executorService)).collect(Collectors.toList());
        CompletableFuture<Void> f1 = CompletableFuture.allOf(list.toArray(new CompletableFuture[]{}));
        System.out.println("全部已经完成了!!" + f1.get());
pool-1-thread-1sleep :0s
pool-1-thread-2sleep :1000s
pool-1-thread-3sleep :2000s
pool-1-thread-4sleep :3000s
pool-1-thread-5sleep :4000s
pool-1-thread-6sleep :5000s
pool-1-thread-7sleep :6000s
pool-1-thread-8sleep :7000s
pool-1-thread-9sleep :8000s
pool-1-thread-10sleep :9000s
pool-1-thread-11sleep :10000s
全部已经完成了!!null

anyOf CompleteableFuture数组里面其中一个完成就返回结果

ExecutorService executorService = Executors.newCachedThreadPool();
        List<CompletableFuture<String>> list = IntStream.rangeClosed(0, 10).mapToObj(i -> CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(i * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "sleep :" + i * 1000 + "s");
            return i + "s";
        }, executorService)).collect(Collectors.toList());
        CompletableFuture<Object> f1 = CompletableFuture.anyOf(list.toArray(new CompletableFuture[]{}));
        System.out.println("其中一个已经完成了!!" + f1.get());
pool-1-thread-1sleep :0s
其中一个已经完成了!!0s