CompletableFuture应用&源码分析

CompletableFuture应用&源码分析

2.1 CompletableFuture介绍

平时多线程开发一般就是使用Runnable,Callable,Thread,FutureTask,ThreadPoolExecutor这些内容和并发编程息息相关。相对来对来说成本都不高,多多使用是可以熟悉这些内容。这些内容组合在一起去解决一些并发编程的问题时,很多时候没有办法很方便的去完成异步编程的操作。

Thread + Runnable:执行异步任务,但是没有返回结果

Thread + Callable + FutureTask:完整一个可以有返回结果的异步任务

  • 获取返回结果,如果基于get方法获取,线程需要挂起在WaitNode里
  • 获取返回结果,也可以基于isDone判断任务的状态,但是这里需要不断轮询

上述的方式都是有一定的局限性的。

比如说任务A,任务B,还有任务C。其中任务B还有任务C执行的前提是任务A先完成,再执行任务B和任务C。

如果任务的执行方式逻辑比较复杂,可能需要业务线程导出阻塞等待,或者是大量的任务线程去编一些任务执行的业务逻辑。对开发成本来说比较高。

CompletableFuture就是帮你处理这些任务之间的逻辑关系,编排好任务的执行方式后,任务会按照规划好的方式一步一步执行,不需要让业务线程去频繁的等待

2.2 CompletableFuture应用

CompletableFuture应用还是需要一内内的成本的。

首先对CompletableFuture提供的函数式编程中三个函数有一个掌握

Supplier<U>  // 生产者,没有入参,有返回结果
Consumer<T>  // 消费者,有入参,但是没有返回结果
Function<T,U>// 函数,有入参,又有返回结果

2.2.1 supplyAsync

CompletableFuture如果不提供线程池的话,默认使用的ForkJoinPool,而ForkJoinPool内部是守护线程,如果main线程结束了,守护线程会跟着一起结束。

public static void main(String[] args)  {
   
    // 生产者,可以指定返回结果
    CompletableFuture<String> firstTask = CompletableFuture.supplyAsync(() -> {
   
        System.out.println("异步任务开始执行");
        System.out.println("异步任务执行结束");
        return "返回结果";
    });

    String result1 = firstTask.join();
    String result2 = null;
    try {
   
        result2 = firstTask.get();
    } catch (InterruptedException e) {
   
        e.printStackTrace();
    } catch (ExecutionException e) {
   
        e.printStackTrace();
    }

    System.out.println(result1 + "," + result2);
}
2.2.2 runAsync

当前方式既不会接收参数,也不会返回任何结果,非常基础的任务编排方式

public static void main(String[] args) throws IOException {
   
    CompletableFuture.runAsync(() -> {
   
        System.out.println("任务go");
        System.out.println("任务done");
    });

    System.in.read();
}
2.2.3 thenApply,thenApplyAsync

有任务A,还有任务B。

任务B需要在任务A执行完毕后再执行。

而且任务B需要任务A的返回结果。

任务B自身也有返回结果。

thenApply可以拼接异步任务,前置任务处理完之后,将返回结果交给后置任务,然后后置任务再执行

thenApply提供了带有Async的方法,可以指定每个任务使用的具体线程池。

public static void main(String[] args) throws IOException {
   
    ExecutorService executor = Executors.newFixedThreadPool(10);

    /*CompletableFuture taskA = CompletableFuture.supplyAsync(() -> {
        String id = UUID.randomUUID().toString();
        System.out.println("执行任务A:" + id);
        return id;
    });
    CompletableFuture taskB = taskA.thenApply(result -> {
        System.out.println("任务B获取到任务A结果:" + result);
        result = result.replace("-", "");
        return result;
    });

    System.out.println("main线程拿到结果:" + taskB.join());*/

    CompletableFuture<String> taskB = CompletableFuture.supplyAsync(() -> {
   
        String id = UUID.randomUUID().toString();
        System.out.println("执行任务A:" + id + "," + Thread.currentThread().getName());
        return id;
    }).thenApplyAsync(result -> {
   
        System.out.println("任务B获取到任务A结果:" + result + "," + Thread.currentThread().getName());
        result = result.replace("-", "");
        return result;
    },executor);

    System.out.println("main线程拿到结果:" + taskB.join());
}
2.2.4 thenAccept,thenAcceptAsync

套路和thenApply一样,都是任务A和任务B的拼接

前置任务需要有返回结果,后置任务会接收前置任务的结果,返回后置任务没有返回值

public static void main(String[] args) throws IOException {
   
    CompletableFuture.supplyAsync(() -> {
   
        System.out.println("任务A");
        return "abcdefg";
    }).thenAccept(result -> {
   
        System.out.println("任务b,拿到结果处理:" + result);
    });

    System.in.read();
}
2.2.5 thenRun,thenRunAsync

套路和thenApply,thenAccept一样,都是任务A和任务B的拼接

前置任务没有返回结果,后置任务不接收前置任务结果,后置任务也会有返回结果

public static void main(String[] args) throws 

你可能感兴趣的:(并发编程,java,开发语言)