1.completableFuture

1、Future接口理论知识复习

一句话:

Future接口可以为主线程开一个分支任务,专门为主线程处理耗时和费力的复杂业务

Future接口(FutureTask实现类)定义了操作异步任务执行一些方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取

消、判断任务执行是否完毕等。

比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务后

主线程就去做其他事情了,忙其它事情或者先执行完,过了一会才去获取子任务的执行结果或变更的任务状态。

举例上课买水案例给大家说明补充。。 。 。 。 。

image-20220910214728506

2、Future接口常用实现类FutureTask异步任务

2.1、Future接口能干什么

FutureJava5新加的一个接口,它提供了一种异步并行计算的功能。

如果主线程需要执行一个很耗时的计算任务,我们就可以通过future把这个任务放到异步线程中执行。主线程继续处理其他任务或者先行

结束,再通过Future获取计算结果。

代码说话:

Runnable接口Callable接口

Future接口和FutureTask实现类

目的:异步多线程任务执行且返回有结果,三个特点:多线程/有返回/异步任务

(班长为老师去买水作为新启动的异步多线程任务且买到水有结果返回)

2.2、本源的Future接口相关架构

image-20220910220518189

image-20220910220745786

FutureTask

多线程/有返回/异步任务


public class CompletableFutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> futureTask = new FutureTask<>(new MyThread());
        Thread t1 = new Thread(futureTask, "t1");
        t1.start();

        System.out.println(futureTask.get());
    }
}


class MyThread implements Callable<String>{

    @Override
    public String call() throws Exception {
        System.out.println("---come in call()");
        return "hello Callable";
    }
}

image-20220910221235068

2.3、Future编码实战和优缺点分析

优点

future+线程池异步多线程任务配合,能显著提高程序的执行效率

public static void main(String[] args) throws ExecutionException, InterruptedException {
    //3个任务,目前开启多个 异步 任务线程来处理,请问耗时多少
    long startTime = System.currentTimeMillis();

    ExecutorService threadPool = Executors.newFixedThreadPool(3);//线程池

    FutureTask<String> futureTask1 = new FutureTask<String>(() -> {
        try {
            TimeUnit.MILLISECONDS.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "task1 over";
    });

    threadPool.submit(futureTask1);

    FutureTask<String> futureTask2 = new FutureTask<String>(() -> {
        try {
            TimeUnit.MILLISECONDS.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "task2 over";
    });

    threadPool.submit(futureTask2);
    System.out.println(futureTask1.get());
    System.out.println(futureTask2.get());
    long endTime = System.currentTimeMillis();
    System.out.println("---costTime" + (endTime - startTime) + "毫秒"); //---costTime505毫秒
    threadPool.shutdown();
}

缺点

get()阻塞

public class FutureAPIDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        FutureTask<String> futureTask = new FutureTask<String>(() -> {
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task over";
        });

        Thread t1 = new Thread(futureTask, "t1");
        t1.start();


        System.out.println(Thread.currentThread().getName()+"\t ---忙其他任务");

        System.out.println(futureTask.get(3,TimeUnit.SECONDS));//过时不候,TimeoutException
    }
}
/**
 *  1、get容易导致阻塞,一般建议放在程序后面,一旦调用不见不散,非要等到结果才会离开,不管你是否计算完成,容易程序阻塞
 *  2、加入我不愿意等待很长时间,我希望过时不候,可以自动离开
 *
 */

idDone()轮询

轮询的方式会耗费无谓的CPU资源,而且也不见得能及时地得到计算结果.

如果想要异步获取结果,通常都会以轮询的方式去获取结果

public class FutureAPIDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        FutureTask<String> futureTask = new FutureTask<String>(() -> {
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task over";
        });

        Thread t1 = new Thread(futureTask, "t1");
        t1.start();

        System.out.println(Thread.currentThread().getName() + "\t ---忙其他任务");

//        System.out.println(futureTask.get());//过时不候,TimeoutException

        while (true){
            if(futureTask.isDone()){
                System.out.println(futureTask.get());
                break;
            }else {
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("正在处理中");
        }
    }
}

image-20220911162316898

结论

Future对于结果的获取不是很友好,只能通过阻塞或轮询的方式得到任务的结果。

2.4、想完成一些复杂的业务

对于简单的业务场景使用Future完全ok

回调通知

应对Future的完成时间,完成了可以告诉我,也就是我们的回调通知

通过轮询的方式去判断任务是否完成这样非常占CPU并且代码也不优雅

创建异步任务

Future+线程池的配合

多个任务前后依赖可以组合处理(水煮鱼)

想将多个异步任务的计算结果组合起来,后一个异步任务的计算结果需要前一个异步任务的值

将两个或多个异步计算合成一个异步计算,这几个异步计算互相独立,同时后面这个又依赖前一个处理的结果。

对计算速度选最快

Future集合中某个任务最快结束时,返回结果,返回第一名处理结果。

。。。。。。。

使用Future之前提供的那点API就囊中羞涩,处理起来不够优雅,

这时候还是让CompletableFuture*以声明式的方式优雅的处理这些需求

ii++

Future能干的,CompletableFuture都能干

3、CompletableFuture对Future的改进

3.1、为什么会出现

get()方法在Future 计算完成之前会一直处在阻塞状态下,

isDone()方法容易耗费CPU资源

对于真正的异步处理我们希望是可以通过传入回调函数,在 Future结束时自动调用该回调函数,这样,我们就不用等待结果。

阻塞的方式和异步编程的设计理念相违背,而轮询的方式会耗费无谓的CPU资源。因此,

JDK8设计出CompletableFuture

CompletableFuture提供了一种观察者模式类似的机制,可以让任务执行完成后通知监听的一方。

3.2、CompletableFuture和CompletionStage源码分别介绍

3.2.1、类架构说明

image-20220911164330614

3.2.2、接口CompletionStage

image-20220911164525843

3.2.3、接口CompletionFuture

image-20220911164728880

3.3、核心的四个静态方法,来创建一个异步任务

image-20220911171501272

不建议new 一个

3.3.1、runAsync 无返回值

public static CompletableFuture<Void> runAsync(Runnable runnable)

public static CompletableFuture<Void>runAsync(Runnable runnable,Executor executor)

3.3.2、supplyAsync 有返回值

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
    
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplierExecutor executor)

3.3.4、上述Executor executor参数说明

没有指定Executor的方法,直接使用默认的ForkJoinPool.commonPool()

作为它的线程池执行异步代码。

如果指定线程池,则使用我们自定义的或者特别指定的线程池执行异步代码

3.3.5、runAsync

public class CompletableFutureBuildDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
            System.out.println(Thread.currentThread().getName());//ForkJoinPool.commonPool-worker-19
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println(completableFuture.get()); //null
    }
}

指定线程池

public class CompletableFutureBuildDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
            System.out.println(Thread.currentThread().getName());//pool-1-thread-1
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },threadPool);
        System.out.println(completableFuture.get()); //null
        threadPool.shutdown();
    }
}

3.3.6、supplyAsync

image-20220911173129592

public class CompletableFutureBuildDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        CompletableFuture<Object> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName());//pool-1-thread-1
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello supplyAsync";
        }, threadPool);
        System.out.println(completableFuture.get());//hello supplyAsync
        threadPool.shutdown();
    }
}

3.3.4、通用演示,减少阻塞和轮询,回调方法(whenComplete)&exceptionally

Java8开始引入了CompletableFuture它是Future的功能增强版,减少阻塞和轮询

可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法

public class CompletableFutureUseDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        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;
        }).whenComplete((r,e)->{
            if (e == null) {
                System.out.println("---计算完成,更新系统UpdateValue:" + r);
            }
        }).exceptionally(e ->{
            e.printStackTrace();
            System.out.println("异常情况" + e.getCause() + "\t" +e.getMessage());
            return null;
        });

        System.out.println(Thread.currentThread().getName() + "线程忙其他任务");

    }
}

发现没有回调函数,主线程已经结束了,这线程类似于守护线程

默认线程池执行完会被shutdown,类似于守护线程

image-20220911175040412


主线程不要立刻结束

    //主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:暂停3秒钟线程
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
public static void main(String[] args) throws ExecutionException, InterruptedException {
    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;
    }).whenComplete((r,e)->{
        if (e == null) {
            System.out.println("---计算完成,更新系统UpdateValue:" + r);
        }
    }).exceptionally(e ->{
        e.printStackTrace();
        System.out.println("异常情况" + e.getCause() + "\t" +e.getMessage());
        return null;
    });

    System.out.println(Thread.currentThread().getName() + "线程忙其他任务");

    //主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:暂停3秒钟线程
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally{
        threadPool.shutdown();
    }
}

image-20220911175428439


解释下为什么默认线程池关闭,自定义线程池记得关闭

public class CompletableFutureUseDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        try {
            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;
            }, threadPool).whenComplete((r, e) -> {
                if (e == null) {
                    System.out.println("---计算完成,更新系统UpdateValue:" + r);
                }
            }).exceptionally(e -> {
                e.printStackTrace();
                System.out.println("异常情况" + e.getCause() + "\t" + e.getMessage());
                return null;
            });

            System.out.println(Thread.currentThread().getName() + "线程忙其他任务");

        } catch (Exception e) {

        }
        //主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:暂停3秒钟线程
/*        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        threadPool.shutdown();
    }

image-20220911192254516


模拟报错

不管是否发生异常都会执行whenComplete

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService threadPool = Executors.newFixedThreadPool(3);
    try {
        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);
            if (result > 5){
                int i = 10/0;
            }
            return result;
        }, threadPool).whenComplete((r, e) -> {
            /*
	        if (e == null) {
                System.out.println("---计算完成,更新系统UpdateValue:" + r);
            }
            */
            System.out.println("---计算完成,更新系统UpdateValue:" + r); //若出异常r为null
        }).exceptionally(e -> {
            e.printStackTrace();
            System.out.println("异常情况" + e.getCause() + "\t" + e.getMessage());
            return null;
        });

        System.out.println(Thread.currentThread().getName() + "线程忙其他任务");

    } catch (Exception e) {

    }
    threadPool.shutdown();
}

直接走到 exceptionally

image-20220911192421678

3.3.5、CompletableFuture的优点

异步任务结束时,会自动回调某个对象的方法;

主线程设置好回调后,不再关心导步任务的执行,异步任务之间可以顺序执行

异步任务出错时,会自动回调某个对象的方法;

4、案例精讲-从电商网站的比价需求说开去

4.1、函数式编程已经主流

4.1.1、面试题

image-20220911194155447

4.2、Lambda表达式+Stream流式调用+Chain链式调用+Java8函数时编程

4.2.1、Runnable

image-20220911194417994

4.2.2、Function

image-20220911194500409

4.2.3、Consumer,BiConsumer

image-20220911194544561

image-20220911194644309

4.2.4、Supplier

image-20220911194821428

4.2.5、小总结

image-20220911194843224

4.2、先说说join和get对比

public class CompletableFutureMallDemo {
    public static void main(String[] args)  {
        /*Student student = new Student();
        student.setId(12).setStudentName("li4").setMajor("english");*/
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            return "hello 1234";
        });
        //System.out.println(completableFuture.get());
        System.out.println(completableFuture.join());//hello 1234 ,不需要抛异常
    }
}

@Data
@Accessors(chain = true)
class Student{
    private Integer id;
    private String studentName;
    private String major;
}

4.3、大厂业务需求说明

切记,功能->性能

电商网站比价需求分析

image-20220911200128545

4.4、一波流Java8函数时编程带走-比价案例实战Case

package org.example;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @PACKAGE_NAME: PACKAGE_NAME
 * @NAME: ConpletableFutureMallDemo
 * @USER: Mrs.Wang
 * @DATE: 2022/9/11
 * @TIME: 19:49
 * @DAY_NAME_SHORT: 周日
 * @DAY_NAME_FULL: 星期日
 * @PROJECT_NAME: JUC
 **/
public class CompletableFutureMallDemo {
    private static List<NetMall> list = Arrays.asList(
            new NetMall("jd"),
            new NetMall("dangdang"),
            new NetMall("taoBao")
    );

    /**
     *  step by step
     * @param list
     * @param productName
     * @return
     */
    public static List<String> getPrice(List<NetMall> list,String productName){
        //《mysql》 in tabao price is 90.43
        return list.stream().
                map(netMall -> String.format(productName + "in %s price is %.2f"
                        , netMall.getNetMallName()
                        , netMall.calcPrice(productName)))
                .collect(Collectors.toList());
    }


    public static List<String> getPriceByCompletableFuture(List<NetMall> list,String productName){
        //《mysql》 in tabao price is 90.43
        List<CompletableFuture<String>> collect = list.stream().
                map(netMall ->
                        //异步,同时去查
                        CompletableFuture.supplyAsync(() -> String.format(productName + "in %s price is %.2f"
                                , netMall.getNetMallName()
                                , netMall.calcPrice(productName))
                        )
                ).collect(Collectors.toList());
        return collect.stream().map(s->s.join()).collect(Collectors.toList());
    }




    public static void main(String[] args)  {
        long startTime = System.currentTimeMillis();
        List<String> mysql = getPrice(list, "mysql");
        for (String s : mysql) {
            System.out.println(s);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("----costTime:"+(endTime-startTime)+"毫秒");

        System.out.println("===========================================");

        long startTime2 = System.currentTimeMillis();
        List<String> mysql2 = getPriceByCompletableFuture(list, "mysql");
        for (String s : mysql2) {
            System.out.println(s);
        }
        long endTime2 = System.currentTimeMillis();
        System.out.println("----costTime:"+(endTime2-startTime2)+"毫秒");}
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class NetMall{
    private String netMallName;
    public double calcPrice(String productName){
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return ThreadLocalRandom.current().nextDouble()*2 + productName.charAt(0);
    }
}

image-20220911203908623


增加网站

private static List<NetMall> list = Arrays.asList(
        new NetMall("jd"),
        new NetMall("dangdang"),
        new NetMall("taoBao"),
        new NetMall("pdd"),
        new NetMall("xy")
);

image-20220911203959420

5、CompletableFuture常用方法

5.1、获得结果getNow和触发计算complete

获取结果

public T get()

public T get(long timeout, TimeUnit unit)

public T join()

/*
没有计算完成的情况下,给我一个替代结果
立即获取结果不阻塞,
	计算完,返回计算完成后的结果,返回complete的结果
	没算完,返回设定的valueIfAbsent值
*/
public T getNow(T valuelfAbsent) 

demo

public class CompletableFutureAPIDemo {

    public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
    {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "abc";
        });
//        System.out.println(completableFuture.get());
//        System.out.println(completableFuture.get(2l,TimeUnit.SECONDS));
//        System.out.println(completableFuture.join());
        System.out.println(completableFuture.getNow("xxx"));
    }
}

触发计算

//是否打断get方法立即返回括号值
当调用completableFuture.get()被阻塞的时候, complete方法就是结束阻塞并get()获取设置的complete里面的值.
public boolean complete(T value)
public class CompletableFutureAPIDemo {

    public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
    {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "abc";
        });
//        System.out.println(completableFuture.get());
//        System.out.println(completableFuture.get(2l,TimeUnit.SECONDS));
//        System.out.println(completableFuture.join());
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
//        System.out.println(completableFuture.getNow("xxx"));

        /**
         * false	abc  			线程计算1秒,主线程2秒
         * true    completeValue 	线程计算2秒,主线程1秒,到这步如果还没有计算完,打断方法立即返回括号值
         */
        System.out.println(completableFuture.complete("completeValue") + "\t" + completableFuture.join());
    }
}

5.2、对计算结果进行处理

5.2.1、thenApply

计算结果存在依赖关系,这两个线程串行化

public class CompletableFutureAPI2Demo {

    public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
    {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("111");
            return 1;
        },threadPool);

        completableFuture.thenApply(f -> {
//            int i = 1/0;
            System.out.println("222");
            return f + 2;
        }).thenApply(f -> {
            System.out.println("333");
            return f + 3;
        }).whenComplete((v,e) ->{
            if (e == null) {
                System.out.println("----计算结果: "+v);
            }
        }).exceptionally(e->{
            e.printStackTrace();
            System.out.println(e.getMessage());
            return null;
        });

        System.out.println(Thread.currentThread().getName()+"---主线程先去忙其他任务");
        threadPool.shutdown();
    }
}

image-20220911214107876

异常相关

  • 由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停

image-20220911214136852


5.2.2、handle

计算结果存在依赖关系,这两个线程串行化

异常相关

    public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
    {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("111");
            return 1;
        }, threadPool);

        completableFuture.handle((f, e) -> {
            int i = 1/0;
            System.out.println("222");
            return f + 2;
        }).handle((f, e) -> {
            System.out.println("333");
            return f + 3;//第二步出异常,导致f == null
        }).whenComplete((v, e) -> {
            if (e == null) {
                System.out.println("----计算结果: " + v);
            }
        }).exceptionally(e -> {
            e.printStackTrace();
            System.out.println(e.getMessage());
            return null;
        });

        System.out.println(Thread.currentThread().getName() + "---主线程先去忙其他任务");
        threadPool.shutdown();
    }
}

image-20220911214445305

5.2.3、总结

image-20220911214537506

5.3、对计算结果进行消费

接受任务的处理结果,并消费处理,无返回结果

.5.3.1、thenAccept

    public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
    {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        }, threadPool);

        completableFuture.thenApply(f -> {
            return f + 2;
        }).thenApply(f -> {
            return f + 3;
        }).thenAccept((r)->{
            System.out.println(r);// 6
        });

        System.out.println(Thread.currentThread().getName() + "---主线程先去忙其他任务");
        threadPool.shutdown();
    }
}

5.3.1、对比补充

Code之任务之间的顺序执行

thenRun

thenRun(Runnable runnable)

任务A执行完执行B,并且B不需要A的结果。B相当于新的线程

thenAccept

thenAccept(Consumer action)

任务A执行完执行BB需要A的结果,但是任务B无返回值

thenApply

thenApply(Function fn)

任务A执行完执行BB需要A的结果,同时任务B有返回值

package org.example;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @PACKAGE_NAME: org.example
 * @NAME: CompletableFutureAPIDemo
 * @USER: Mrs.Wang
 * @DATE: 2022/9/11
 * @TIME: 20:46
 * @DAY_NAME_SHORT: 周日
 * @DAY_NAME_FULL: 星期日
 * @PROJECT_NAME: JUC
 **/
public class CompletableFutureAPI3Demo {

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

        System.out.println(CompletableFuture.supplyAsync(() -> "resultA")
                .thenRun(() -> {
                }).join());  													// null

        System.out.println(CompletableFuture.supplyAsync(() -> "resultA")
                .thenAccept((r) -> System.out.println(r) /*resultA*/).join()); //null

        System.out.println(CompletableFuture.supplyAsync(() -> "resultA")
                .thenApply((r) -> r + " resultB").join()); 						//resultA resultB
    }
}

image-20220911215856346

5.4、CompleteFuture和线程池说明

5.4.1、以thenRun和thenRunAsync为例,有什么区别?

都是thenRun

public class CompletableFutureWithThreadPoolDemo {

    public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
    {
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        try {
            CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> {

                try {
                    TimeUnit.MILLISECONDS.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("1号任务" + "\t" + Thread.currentThread().getName());
                return "abcd";
            },threadPool).thenRun(() -> {

                try {
                    TimeUnit.MILLISECONDS.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("2号任务" + "\t" + Thread.currentThread().getName());
            }).thenRun(() -> {

                try {
                    TimeUnit.MILLISECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("3号任务" + "\t" + Thread.currentThread().getName());
            }).thenRun(() -> {

                try {
                    TimeUnit.MILLISECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("4号任务" + "\t" + Thread.currentThread().getName());
            });

            completableFuture.get(2l,TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
        
    }
}

发现用的是同一个线程池

image-20220911221205958


第一个线程后面变为thenRunAsync

package org.example;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @PACKAGE_NAME: org.example
 * @NAME: CompletableFutureAPIDemo
 * @USER: Mrs.Wang
 * @DATE: 2022/9/11
 * @TIME: 20:46
 * @DAY_NAME_SHORT: 周日
 * @DAY_NAME_FULL: 星期日
 * @PROJECT_NAME: JUC
 **/
public class CompletableFutureWithThreadPoolDemo {

    public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
    {
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        try {
            CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> {

                try {
                    TimeUnit.MILLISECONDS.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("1号任务" + "\t" + Thread.currentThread().getName());
                return "abcd";
            },threadPool).thenRunAsync(() -> {  // 变为thenRunAsync

                try {
                    TimeUnit.MILLISECONDS.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("2号任务" + "\t" + Thread.currentThread().getName());
            }).thenRun(() -> {

                try {
                    TimeUnit.MILLISECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("3号任务" + "\t" + Thread.currentThread().getName());
            }).thenRun(() -> {

                try {
                    TimeUnit.MILLISECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("4号任务" + "\t" + Thread.currentThread().getName());
            });

            completableFuture.get(2l,TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }

    }
}

发现又回到了默认线程池

image-20220911221351915

5.4.2、小总结

  • 没有传入自定义线程池,都用默认线程池ForkJoinPool;

  • 传入了一个自定义线程池,

如果你执行第一个任务的时候,传入了一个自定义线程池:

调用thenRun方法执行第二个任务时,则第二个任务和第一个任务是共用同一个线程池。

调用thenRunAsync执行第二个任务时,则第一个任务使用的是你自己传入的线程池,第二个任务使用的是ForkJoin线程池

  • 备注

有可能处理太快,系统优化切换原则,直接使用main线程处理

其它如: thenAccept和thenAcceptAsyncthenApply和thenApplyAsync等,它们之间的区别也是同理

public class CompletableFutureWithThreadPoolDemo {

    public static void main(String[] args) //throws ExecutionException, InterruptedException, TimeoutException
    {
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        try {
            CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> {
                
                System.out.println("1号任务" + "\t" + Thread.currentThread().getName());
                return "abcd";
            },threadPool).thenRun(() -> {

                System.out.println("2号任务" + "\t" + Thread.currentThread().getName());
            }).thenRun(() -> {


                System.out.println("3号任务" + "\t" + Thread.currentThread().getName());
            }).thenRun(() -> {
                
                System.out.println("4号任务" + "\t" + Thread.currentThread().getName());
            });

            completableFuture.get(2l,TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }

    }
}

image-20220911222103054


5.4.3、源码分析

image-20220911222738801

5.5、对计算速度进行选用

5.5.1、谁快用谁

5.5.2、applyToEither

public class CompletableFutureFastDemo {
    public static void main(String[] args) {
        CompletableFuture<String> playA = CompletableFuture.supplyAsync(() -> {
            System.out.println("A come in");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "playA";
        });
        CompletableFuture<String> playB = CompletableFuture.supplyAsync(() -> {
            System.out.println("B come in");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "playB";
        });

        CompletableFuture<String> result = playA.applyToEither(playB, f -> f + " is winner");
        System.out.println(Thread.currentThread().getName() + "\t" + "------: " + result.join());
    }
}

image-20220911230535591

5.6、对计算结果进行合并

两个CompletionStage任务都完成后,最终能把两个任务的结果一起交给thenCombine来处理

先完成的先等着,等待其他分支任务

5.6.1、thenCombine

标准版

public class CompletableFutureCombineDemo {
    public static void main(String[] args) {
        CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t---启动");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 10;
        });
        CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t---启动");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 20;
        });

        CompletableFuture<Integer> result = completableFuture1.thenCombine(completableFuture2, (c1, c2) -> {
            System.out.println("----开始两个结果合并");
            return c1 + c2;
        });

        System.out.println(result.join());

    }
}

image-20220911231508525

表达式

public class CompletableFutureCombineDemo {
    public static void main(String[] args) {

        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t---启动");
            return 10;
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t---启动");
            return 20;
        }), (c1, c2) -> {
            return c1 + c2;
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t---启动");
            return 30;
        }), (c1, c2) -> {
            return c1 + c2;
        });

        System.out.println(completableFuture.join());
    }
}

image-20220911232303522

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值