Java8 CompletableFuture

package com.example.cesium.utils;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ForkJoinPool;

public class CompletableFutureDemo {

    public static void main(String[] args) {
        //doSupplyAsync();//开启一个带返回值的异步任务 ---  小白在打王者和厨师做饭 应该为并行操作
        //doThenCompose();//连接两个异步任务 ---  小白在打王者 和 (厨师做饭,然后 服务员打饭)并行操作
        //doThenCombine();//合并两个异步任务 ---  小白打王者 厨师炒饭 服务员焖饭 三个并行
        //doThenApply();// 任务后置处理(同一个线程) ---  小白接电话,(服务员收款,然后 服务员开发票)并行
        //doThenApplyAsync();// 任务后置处理(不同线程) --- 小白接电话,(服务员收款,然后 另一个服务员开发票)并行
        //doApplyToEither();//用来获取最先完成的任务 ---  比较700路 和 800路 哪个先到
        //doApplyToEither2();// 比较700路 和 800路 哪个先到 , 坐上700路撞树了
        //doExceptionally();//对于异常的处理,除了尾部也可以中间加

        System.out.println(Runtime.getRuntime().availableProcessors());
        System.out.println(ForkJoinPool.commonPool().getPoolSize());
        System.out.println(ForkJoinPool.getCommonPoolParallelism());
    }

    private static void doExceptionally(){
        SmallTool.printTimeAndThread("小白走出餐厅 , 来到公共汽车站");
        SmallTool.printTimeAndThread("等待 700路 或者 800路 公交车到来");

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            SmallTool.printTimeAndThread("700路公交正在赶来");
            SmallTool.sleepMillis(100);
            return "700路到了";
        }).applyToEither(CompletableFuture.supplyAsync(() -> {
            SmallTool.printTimeAndThread("800路公交正在赶来");
            SmallTool.sleepMillis(200);
            return "800路到了";
        }), firstBus -> {
            SmallTool.printTimeAndThread(firstBus);
            if(firstBus.startsWith("700")){
                throw new RuntimeException("撞树了。。。");
            }
            return firstBus;
        }).exceptionally(e->{
            SmallTool.printTimeAndThread(e.getMessage());
            SmallTool.printTimeAndThread("小白叫出租车");
            return "出租车叫到了";
        });

        SmallTool.printTimeAndThread(String.format("%s,小白坐车回家",future.join()));
    }

    private static void doApplyToEither2(){
        SmallTool.printTimeAndThread("小白走出餐厅 , 来到公共汽车站");
        SmallTool.printTimeAndThread("等待 700路 或者 800路 公交车到来");

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            SmallTool.printTimeAndThread("700路公交正在赶来");
            SmallTool.sleepMillis(100);
            return "700路到了";
        }).applyToEither(CompletableFuture.supplyAsync(() -> {
            SmallTool.printTimeAndThread("800路公交正在赶来");
            SmallTool.sleepMillis(200);
            return "800路到了";
        }), firstBus -> {
            SmallTool.printTimeAndThread(firstBus);
            if(firstBus.startsWith("700")){
                throw new RuntimeException("撞树了。。。");
            }
            return firstBus;
        });

        SmallTool.printTimeAndThread(String.format("%s,小白坐车回家",future.join()));
    }

    private static void doApplyToEither(){
        SmallTool.printTimeAndThread("小白走出餐厅 , 来到公共汽车站");
        SmallTool.printTimeAndThread("等待 700路 或者 800路 公交车到来");

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            SmallTool.printTimeAndThread("700路公交正在赶来");
            SmallTool.sleepMillis(100);
            return "700路到了";
        }).applyToEither(CompletableFuture.supplyAsync(() -> {
            SmallTool.printTimeAndThread("800路公交正在赶来");
            SmallTool.sleepMillis(200);
            return "800路到了";
        }), (firstBus -> firstBus));

        SmallTool.printTimeAndThread(String.format("%s,小白坐车回家",future.join()));
    }

    private static void doThenApplyAsync(){
        SmallTool.printTimeAndThread("小白吃好了");
        SmallTool.printTimeAndThread("小白 结账、要求开发票");

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            SmallTool.printTimeAndThread("服务员收款 500元");
            SmallTool.sleepMillis(100);
            return "500";
        }).thenApplyAsync(money -> {
            SmallTool.printTimeAndThread(String.format("服务员开发票, 面额 %s元",money));
            SmallTool.sleepMillis(200);
            return String.format("%s元发票",money);
        });

        SmallTool.printTimeAndThread("小白 接到朋友电话,想一起打游戏");
        SmallTool.printTimeAndThread(String.format("小白拿到%s,准备回家",future.join()));
    }

    private static void doThenApply(){
        SmallTool.printTimeAndThread("小白吃好了");
        SmallTool.printTimeAndThread("小白 结账、要求开发票");

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            SmallTool.printTimeAndThread("服务员收款 500元");
            SmallTool.sleepMillis(100);
            return "500";
        }).thenApply(money -> {
            SmallTool.printTimeAndThread(String.format("服务员开发票, 面额 %s元",money));
            SmallTool.sleepMillis(200);
            return String.format("%s元发票",money);
        });

        SmallTool.printTimeAndThread("小白 接到朋友电话,想一起打游戏");
        SmallTool.printTimeAndThread(String.format("小白拿到%s,准备回家",future.join()));
    }

    private static void doThenCombine(){
        SmallTool.printTimeAndThread("小白进入餐厅");
        SmallTool.printTimeAndThread("小白点了 番茄炒蛋 + 一碗米饭");

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            SmallTool.printTimeAndThread("厨师炒菜");
            SmallTool.sleepMillis(200);
            return "番茄炒蛋";
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            SmallTool.printTimeAndThread("服务员焖米饭");
            SmallTool.sleepMillis(300);
            return "米饭";
        }), (dish, rice) -> {
            SmallTool.printTimeAndThread("服务员打饭");
            SmallTool.sleepMillis(100);
            return String.format("%s + %s 好了", dish, rice);
        });
        SmallTool.printTimeAndThread("小白在打王者");
        SmallTool.printTimeAndThread(String.format("%s, 小白开吃",future.join()));
    }

    private static void doThenCompose(){
        SmallTool.printTimeAndThread("小白进入餐厅");
        SmallTool.printTimeAndThread("小白点了 番茄炒蛋 + 米饭");

        CompletableFuture<Object> future = CompletableFuture.supplyAsync(() -> {
            SmallTool.printTimeAndThread("厨师炒菜");
            SmallTool.sleepMillis(200);
            return "番茄炒蛋";
        }).thenCompose(dish -> CompletableFuture.supplyAsync(()->{
            SmallTool.printTimeAndThread("服务员打饭");
            SmallTool.sleepMillis(100);
            return dish + "米饭";
        }));

        SmallTool.printTimeAndThread("小白在打王者");
        SmallTool.printTimeAndThread(String.format("%s,小白开吃",future.join()));
    }

    /**
     * 1.小白进入餐厅
     * 2.小白点了 番茄炒饭 + 一碗米饭
     * 3.小白在打王者
     * 4.厨师炒菜  200ms
     * 5.厨师打饭  100ms
     * 6.小白开吃
     */
    private static void doSupplyAsync(){
        SmallTool.printTimeAndThread("小白进入餐厅");
        SmallTool.printTimeAndThread("小白点了 番茄炒饭 + 一碗米饭");

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
              SmallTool.printTimeAndThread("厨师炒菜");
              SmallTool.sleepMillis(200);
              SmallTool.printTimeAndThread("厨师打饭");
              SmallTool.sleepMillis(100);
              return "番茄炒蛋 + 米饭 做好了";
        });

        SmallTool.printTimeAndThread("小白在打王者");
        SmallTool.printTimeAndThread(String.format("%s , 小白开吃",future.join()));
    }

    //

    //

    //

}

常用API
任务执行
supplyAsync:有返回值
runAsync:无返回值
任务接力
thenRun thenRunAsync
thenAccept thenAcceptAsync
thenApply thenApplyAsync
handle handleAsync
applyToEither applyToEitherAsync
acceptEither acceptEitherAsync
runAfterEither runAfterEitherAsync
thenCombine thenCombineAsync
thenAcceptBoth thenAcceptBothAsync
说明
带run的方法,无入参,无返回值。
带accept的方法,有入参,无返回值。
带supply的方法,无入参,有返回值。
带apply的方法,有入参,有返回值。
带handle的方法,有入参,有返回值,并且带异常处理。
以Async结尾的方法,都是异步的,否则是同步的。
以Either结尾的方法,只需完成任意一个。
以Both/Combine结尾的方法,必须所有都完成。
任务结果获取
join 阻塞等待,不会抛异常
get 阻塞等待,会抛异常
complete(T value) 不阻塞,如果任务已完成,返回处理结果。如果没完成,则返回传参value。
completeExceptionally(Throwable ex) 不阻塞,如果任务已完成,返回处理结果。如果没完成,抛异常。

 

 

基于以上说明,再举一个在实际工作中遇到的问题以及解决。

场景:导出所有点、线、面 有序 数据并封装json,速度慢 1-2秒。

思路:使用CompletableFuture的异步跑点线面三个不同线程,并把三个线程组成一个task,监听task中的子任务,执行完成后封装到结果集

实现:

public JSONObject getAllGeoJson(Long miningId) throws IOException {
        JSONArray features = new JSONArray();
        JSONObject geoJSON = new JSONObject();
        geoJSON.put("type", "FeatureCollection");
        CompletableFuture<JSONArray> roadTask = CompletableFuture.supplyAsync(() -> {
            return roadService.findAllInfo2(miningId);
        }).exceptionally(e -> {
            e.printStackTrace();
            return new JSONArray();
        });
        CompletableFuture<JSONArray> zoneTask = CompletableFuture.supplyAsync(() -> {
            return workzoneService.findAllInfo2(miningId);
        }).exceptionally(e -> {
            e.printStackTrace();
            return new JSONArray();
        });
        CompletableFuture<JSONArray> pointTask = CompletableFuture.supplyAsync(() -> {
            try {
                return workPointService.findAllInfo(miningId);
            } catch (IOException e) {
                e.printStackTrace();
                return new JSONArray();
            }
        }).exceptionally(e -> {
            return new JSONArray();
        });

        CompletableFuture<Void> allFirstTasks = CompletableFuture.allOf(pointTask, roadTask, zoneTask);
        allFirstTasks.thenRun(() -> {
            features.add(pointTask.join());
            features.add(roadTask.join());
            features.add(zoneTask.join());
        }).join();
        geoJSON.put("features", features);
        return geoJSON;
    }

 

posted @ 2022-12-14 12:29  蔡徐坤1987  阅读(45)  评论(0编辑  收藏  举报